diff --git a/apps/docs/content/features/coding-agents.mdx b/apps/docs/content/features/coding-agents.mdx
index dca29ed04..d956ab9c6 100644
--- a/apps/docs/content/features/coding-agents.mdx
+++ b/apps/docs/content/features/coding-agents.mdx
@@ -36,7 +36,7 @@ Most coding-agent platforms went agent-first, then bolted on infrastructure —
### Your agent, your subscription
-Bring whichever agent you already use. Claude Code today; Codex, Gemini CLI, opencode, and any MCP-capable client next. The container is a regular Ubuntu — install your own CLI tools, drop in your `.claude` / `.cursor` configs, attach your IDE over SSH. **Zerops doesn't resell tokens or proxy your model calls** — sign in with your own Anthropic / OpenAI / Google subscription and the agent talks to its provider directly.
+ZCP supports multiple coding agents including Claude Code (Anthropic), Codex (OpenAI), Antigravity, and Grok Build. The container is a regular Ubuntu — install your own CLI tools, drop in your `.claude` / `.cursor` configs, attach your IDE over SSH. **Zerops doesn't resell tokens or proxy your model calls** — sign in with your own Anthropic / OpenAI / Google subscription and the agent talks to its provider directly.
### An ordinary Zerops project underneath
@@ -56,7 +56,7 @@ Runtimes for Bun, Deno, Node.js, Go, Python, Rust, Java, .NET, PHP, Elixir, Glea
The agent reaches your project's private network one of two ways:
-- **Remote** — a `zcp` service deployed into the project runs the agent. You attach to it with Claude Code's IDE extension, with any IDE that supports remote development (Cursor, Windsurf, VS Code Remote), or by running [`zcli vpn up`](/references/networking/vpn) and ssh-ing into `zcp` to drive the rest of the project from a shell.
+- **Remote** — a `zcp` service deployed into the project runs the agent. You attach to it with your agent's IDE extension or terminal, with any IDE that supports remote development (Cursor, Windsurf, VS Code Remote), or by running [`zcli vpn up`](/references/networking/vpn) and ssh-ing into `zcp` to drive the rest of the project from a shell.
- **Local** — install the `zcp` MCP on your machine and run `zcli vpn up` to join the network. From there your IDE, agent, and shell can ssh directly into any container.
Either way, the agent reaches [managed services by hostname](/references/networking/internal-access) (`db:5432`, `cache:6379`), deploys through the [Zerops pipeline](/features/pipeline), and reads logs and events the same way you would.
@@ -173,7 +173,7 @@ With the model clear, here's where ZCP sits among adjacent tools. People say "ag
-
The agent runs on your machine, edits your local checkout, runs local commands. Excellent at code changes. **MCP** is now native across these tools, so external reach — databases, networking, deploy targets, runtime logs — comes through plugins instead of bare hands. The agent still lives on your laptop, though: anything off-machine has to be reached, not *inhabited*. Install the ZCP MCP locally and run `zcli vpn up`, and any of these agents can now reach a real Zerops project alongside your local code: services addressed by hostname, deploys, logs, events.
@@ -211,7 +211,7 @@ With the model clear, here's where ZCP sits among adjacent tools. People say "ag
## Where to start
{
+ const client = new Client({
+ host: config.db.host,
+ port: config.db.port,
+ user: config.db.username,
+ password: config.db.password,
+ database: config.db.database,
+ });
+
+ await client.connect();
+
+ await client.query(`
+ CREATE TABLE IF NOT EXISTS clicks (
+ id SERIAL PRIMARY KEY,
+ seed INTEGER NOT NULL,
+ clicked_at TIMESTAMPTZ DEFAULT NOW()
+ )
+ `);
+
+ return client;
+};
+```
+
+**Replace `src/app.ts`** with this:
+
+```ts
+import express from 'express';
+import path from 'path';
+import { connectDB } from './db';
+
+const app = express();
+
+app.use(express.static(path.join(__dirname, '../public')));
+
+app.get('/count', async (_, res) => {
+ const client = await connectDB();
+ const result = await client.query(
+ 'SELECT seed FROM clicks ORDER BY id ASC LIMIT 20'
+ );
+ const countResult = await client.query('SELECT COUNT(*) FROM clicks');
+ await client.end();
+ res.json({
+ count: parseInt(countResult.rows[0].count),
+ seeds: result.rows.map((r) => r.seed),
+ });
+});
+
+app.post('/click', async (_, res) => {
+ const client = await connectDB();
+ const seed = Math.floor(Math.random() * 1000000);
+ await client.query('INSERT INTO clicks (seed) VALUES ($1)', [seed]);
+ const countResult = await client.query('SELECT COUNT(*) FROM clicks');
+ await client.end();
+ res.json({ count: parseInt(countResult.rows[0].count), seed });
+});
+
+app.get('/status', (_, res) => {
+ res.status(200).send({ status: 'UP' });
+});
+
+export default app;
+```
+
+**Create a `public/` folder** at the repo root and add `public/index.html`:
+
+
+
+```html
+
+
+
+
+
+ Zerops Quickstart
+
+
+
+
+
+ zerops
+
+
You made it. 🎉
+
+ You just deployed a real app: managed database, private network,
+ auto-deploy. Let us know you made it through.
+
+
+
+ ...
+
+
+
+
+
+ Node.js 20
+ PostgreSQL 16
+ Zerops
+
+
+
+
+
+```
+
+
+
+The `zerops.yml` already exists in the repo. Update `deployFiles` to include the `public` folder:
+
+```yaml
+zerops:
+ - setup: app
+ build:
+ base: nodejs@20
+ prepareCommands:
+ - npm install -g typescript
+ buildCommands:
+ - npm i
+ - npm run build
+ deployFiles:
+ - ./dist
+ - ./node_modules
+ - ./public
+ - ./package.json
+ run:
+ base: nodejs@20
+ ports:
+ - port: 3000
+ httpSupport: true
+ envVariables:
+ NODE_ENV: production
+ DB_NAME: db
+ DB_HOST: ${db_hostname}
+ DB_USER: ${db_user}
+ DB_PASSWORD: ${db_password}
+ # or use the full connection string:
+ # DB_CONNECTION_STRING: ${db_connectionString}
+ start: npm run start:prod
+ healthCheck:
+ httpGet:
+ port: 3000
+ path: /status
+```
+
+:::tip How Zerops env variables work
+Zerops automatically generates credentials for every managed service. The variable names are derived from the service hostname — so if your database service is named `db`, the variables are `${db_hostname}`, `${db_user}`, `${db_password}`, and `${db_connectionString}`. If you named it `postgres` instead, they'd be `${postgres_hostname}`, `${postgres_password}`, and so on.
+:::
+
+Push to your repo and connect GitHub in the next section.
+
+```bash
+git add .
+git commit -m "add feedback app"
+git push
+```
+
+:::note Want to build something else instead?
+Skip the feedback app. Pick the recipe matching your stack from [app.zerops.io/recipes](https://app.zerops.io/recipes), add a `zerops.yaml` to your repo root copying the structure from the recipe, and adjust `buildCommands`, `deployFiles`, and `start` for your stack. The database env variables (`${db_hostname}`, `${db_user}`, `${db_password}`) stay the same regardless of what you're building.
+:::
+
+### Connect GitHub and auto-deploy
+
+1. Click into your **app** service
+2. Scroll down to **Pipelines & CI/CD settings**
+3. Click **GitHub** to connect your repo
+4. Select your repo and set **Trigger on** to **Push to Branch**, pick `main`
+5. In the **"Which `setup` from zerops.yml to use"** field, type `app`
+6. Click **Activate pipeline trigger**
+
+That's it. Every push to main now builds and deploys automatically. Zero downtime, Zerops runs the new version alongside the old one, waits for a health check, then switches traffic over.
+
+You can also trigger deploys manually with the Zerops CLI: `zcli push`.
+
+### Add yourself to the list
+
+Deployed the feedback app? Open your live app URL and click **"I followed the Zerops quickstart"**. You'll show up alongside everyone else who's made it through.
+
+Check out everyone who's already made it: [app-25be-3000.prg1.zerops.app](https://app-25be-3000.prg1.zerops.app/)
+
+### If something breaks
+
+Got a 502 or an app crash on startup? Start here.
+
+**Check the runtime logs first.** Dashboard, click your app service, click the three-dot menu, then **Runtime log**. The error will be there, usually in the last few lines.
+
+Two things come up most often on a first deploy:
+
+
+
+
+Your `node_modules` aren't being deployed. Either:
+
+- Add `node_modules` to `deployFiles` in `zerops.yaml` (quick fix)
+- Or use `output: standalone` in `next.config.mjs` (better for Next.js, bundles everything you need)
+
+
+
+
+Your environment variables aren't set correctly in `zerops.yaml`. Copy this exactly:
+
+```yaml
+DB_HOST: ${db_hostname}
+DB_USER: ${db_user}
+DB_PASSWORD: ${db_password}
+DB_NAME: db
+```
+
+Variable names are derived from your database service hostname. If your db service is named `db`, use `${db_hostname}`, `${db_user}`, `${db_password}`. If you named it something else, swap `db_` for that name.
+
+
+
+
+:::tip Debug locally with VPN
+Install zcli first (see [CLI reference](/references/cli)), then run `zcli vpn up [your-project-id]` and your machine joins the project's private network. You can connect to `db:5432` directly from your local machine using TablePlus, psql, or any database client. You can disable SSL when connecting over VPN - the tunnel itself handles security either way. If `db` doesn't resolve, try `db.zerops` instead.
+:::
+
+### What's next
+
+- **[SSH into your container](/references/networking/ssh)**: `zcli service shell [service-name]` for full Linux access
+- **[Custom domain](/references/networking/public-access)**: add your domain, SSL is automatic
+- **[Autoscaling](/features/scaling)**: set min and max CPU and RAM, Zerops scales within that range automatically
+- **[Add more services](/features/infrastructure)**: queues, search engines, object storage, just add them to your project
+- **[Try ZCP](/zcp/quickstart)**: Zerops' AI agent that can deploy, debug, and operate your project
+
+:::note Stuck?
+Jump into the [Zerops Discord](https://docs.zerops.io/discord). The community is active and the team is there.
+:::
diff --git a/apps/docs/content/quickstart/quickstart.mdx b/apps/docs/content/quickstart/quickstart.mdx
new file mode 100644
index 000000000..da99298f9
--- /dev/null
+++ b/apps/docs/content/quickstart/quickstart.mdx
@@ -0,0 +1,116 @@
+---
+title: Quickstart
+description: Deploy a live app with a managed database and a public URL. Takes about 5 minutes.
+sidebar_label: Quickstart
+sidebar_position: 1
+custom_edit_url: null
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import Video from '@site/src/components/Video';
+import Image from '/src/components/Image';
+
+In the next 5 minutes, we'll go from zero to a live app: a managed database, a public URL, and auto-deploy on every git push, all set up for you.
+
+Here's what we're building together: a page with a button that says **"I followed the Zerops quickstart"**. Every developer who finishes this guide and clicks it gets added to the wall. It's a real app, Express backend, PostgreSQL database, static frontend, running entirely on **Zerops**.
+
+Curious what you'll end up with? Here it is, live: [app-25be-3000.prg1.zerops.app](https://app-25be-3000.prg1.zerops.app/)
+
+
+
+:::tip Before we start
+Sign up at [app.zerops.io](https://app.zerops.io). You get $15 in promo credits on signup, no credit card needed. Verify your account with a $10 payment and get an additional $50, bringing your total to $65 in credits. A simple app with a database costs roughly $3-5/month, so credits go a long way.
+:::
+
+---
+
+## 1. Deploy the recipe
+
+Go to [app.zerops.io/recipes](https://app.zerops.io/recipes). No account needed, the recipes page works even when you're not logged in.
+
+For this guide, find and click **Node.js**. You'll see **Node.js Hello World**, a Node.js app with Express connected to a PostgreSQL database.
+
+Hit **Deploy nodejs-hello-world-small-prod**. If you're not signed in yet, Zerops creates your account and kicks off the deploy in the same step.
+
+
+
+
+
+:::info What's a recipe?
+A recipe is a working app with infrastructure already configured: managed database, environment variables, `zerops.yaml`, everything connected. It's a correct starting point, not a finished product.
+:::
+
+---
+
+## 2. Watch it build
+
+After hitting Deploy, you'll land on the dashboard. On the right side you'll see a pipeline already running.
+
+It goes through these steps in real time:
+
+1. Initializing build container
+2. Running build commands from `zerops.yaml`
+3. Creating app version and upgrading service
+4. Done
+
+
+
+:::tip Good to know
+The build container is **temporary and free**. Zerops spins it up, runs your build, saves the output, and deletes it. You're only billed for the running app.
+:::
+
+Once the pipeline finishes, your app is live.
+
+---
+
+## 3. See what got created
+
+Click into your new project. You'll see:
+
+- **app**: your Node.js service, already running
+- **db**: a managed PostgreSQL database, already running
+- **Project core**: load balancer, firewall, logger, all managed by Zerops
+
+All of these are already talking to each other on a private network. Nothing to configure.
+
+
+---
+
+## 4. Open your live app
+
+The Zerops subdomain is already enabled when you deploy from a recipe. Click into your **app** service and open the URL.
+
+The default recipe app will be there.
+
+When you're ready for production, point a custom domain at your app. Zerops handles the SSL certificate automatically.
+
+---
+
+## You're live 🎉
+
+Here's what's running:
+
+- A real app on production infrastructure
+- A managed PostgreSQL database, ready to use
+- All services on a private network, secure by default
+- Full Linux containers for your app — SSH in anytime, install anything
+
+None of the infrastructure needed manual configuration.
+
+:::note Stuck?
+Jump into the [Zerops Discord](https://docs.zerops.io/discord). The community is active and the team is there.
+:::
+
+---
+
+Your app is live and the infrastructure is running.
+
+**Next up:** Swap the recipe for the feedback app we showed you, connect GitHub for auto-deploy, and add yourself to the wall. [Deploy your first app →](/quickstart/deploy-your-first-app)
diff --git a/apps/docs/content/zcp/glossary.mdx b/apps/docs/content/zcp/glossary.mdx
index b9012bcdc..f49f7391e 100644
--- a/apps/docs/content/zcp/glossary.mdx
+++ b/apps/docs/content/zcp/glossary.mdx
@@ -27,7 +27,7 @@ Use these definitions when a page, workflow status, agent handoff, or policy nee
**Remote setup** - the `zcp` binary running inside a Zerops `zcp@1` service.
-**Include Coding Agent** - remote setup option that adds the bundled agent CLI, currently Claude Code, and preconfigures it to use ZCP MCP tools.
+**Include Coding Agent** - remote setup option that adds a bundled agent CLI (Claude Code, Codex, Antigravity, or Grok Build) and preconfigures it to use ZCP MCP tools.
**Cloud IDE** - browser-based VS Code served by remote setup.
diff --git a/apps/docs/content/zcp/overview.mdx b/apps/docs/content/zcp/overview.mdx
index fbaf5ebe0..acfb66e67 100644
--- a/apps/docs/content/zcp/overview.mdx
+++ b/apps/docs/content/zcp/overview.mdx
@@ -5,10 +5,6 @@ description: 'How the ZCP MCP server lets a coding agent work with one real Zero
import Image from '/src/components/Image';
-:::info Public preview
-ZCP MCP is a public preview and is under active development. If you hit a bug, confusing behavior, or a missing workflow, please report it on Discord; feedback from real projects is especially useful.
-:::
-
This section covers, in order:
@@ -129,7 +125,7 @@ To start, add remote setup in Zerops or initialize local setup beside your edito
@@ -137,7 +133,7 @@ To start, add remote setup in Zerops or initialize local setup beside your edito
## Your agent, credentials, and workspace
-**Agent account.** Remote setup can include a bundled agent CLI, currently Claude Code, already configured for MCP. Zerops wires the agent to the tools; you still authenticate with your own subscription login or API credentials.
+**Agent account.** ZCP supports multiple coding agents including Claude Code (Anthropic), Codex (OpenAI), Antigravity, and Grok Build. Remote setup can bundle one of these, already configured for MCP. Zerops wires the agent to the tools; you still authenticate with your own subscription login or API credentials.
**Zerops token.** The MCP server connects through `ZCP_API_KEY`, a Zerops token limited to one project. Remote setup gets it from the platform; local setup reads it from `.mcp.json`. Token details live in [Tokens and credentials](/zcp/security/tokens-and-project-access).
diff --git a/apps/docs/content/zcp/quickstart.mdx b/apps/docs/content/zcp/quickstart.mdx
index c41570832..c1c9ccd87 100644
--- a/apps/docs/content/zcp/quickstart.mdx
+++ b/apps/docs/content/zcp/quickstart.mdx
@@ -1,12 +1,14 @@
---
title: 'Quickstart'
-description: 'Try ZCP with a ready-made AI Agent recipe, Browser VS Code, Claude Code, and one product change.'
+description: 'Try ZCP with a ready-made AI Agent recipe, Browser VS Code, a bundled coding agent, and one product change.'
---
import Image from '/src/components/Image';
import Icons from '@theme/Icon';
-Use this when you want the fastest hands-on ZCP loop: deploy an **AI Agent** recipe, authorize Claude Code, open Browser VS Code, and ask for one product change.
+Use this when you want the fastest hands-on ZCP loop: deploy an **AI Agent** recipe, authorize your coding agent, open Browser VS Code, and ask for one product change.
+
+ZCP supports multiple coding agents including Claude Code (Anthropic), Codex (OpenAI), Antigravity, and Grok Build. The screenshots below use Claude Code as the walkthrough example.
Some [Zerops recipes](https://app.zerops.io/recipes) include an **AI Agent** environment. That preset creates app services, managed services, the `zcp@1` workspace, Browser VS Code, and bundled agent wiring in one deploy.
@@ -15,7 +17,7 @@ This quickstart uses [Laravel showcase](https://app.zerops.io/recipes/laravel-sh
## Prerequisites
- A Zerops account with permission to create a project.
-- A Claude Code subscription login or API authentication. Zerops wires Claude Code to ZCP, but your agent subscription or model credentials stay yours.
+- A subscription login or API credentials for your chosen coding agent (Claude Code, Codex, Antigravity, or Grok Build). Zerops wires the agent to ZCP, but your agent subscription or model credentials stay yours.
## 1. Choose the AI Agent recipe
@@ -37,11 +39,11 @@ This quickstart uses [Laravel showcase](https://app.zerops.io/recipes/laravel-sh
The deploy creates app runtimes, managed dependencies, and a `zcp@1` workspace. In this recipe it appears as the `zcp` service. The agent, terminal, and browser IDE run there. App code still deploys to the app runtimes, not to `zcp`.
-## 2. Authorize Claude Code
+## 2. Authorize your coding agent
-When provisioning finishes, the dashboard opens the Claude Code authentication flow. Use your own Claude Code subscription login or API credentials.
+When provisioning finishes, the dashboard opens the authentication flow for your bundled agent. If you are using Claude Code (as in the screenshots below), use your own Claude Code subscription login or API credentials.
-This is separate from `ZCP_API_KEY`, the Zerops token used by ZCP. Your Claude login or API key is used only by the bundled agent.
+This is separate from `ZCP_API_KEY`, the Zerops token used by ZCP. Your agent login or API key is used only by the bundled agent.
If you close the prompt, open the `zcp` service in the dashboard. Its panel shows the browser workspace, web terminal, SSH access, desktop editor access, and agent authorization state.
@@ -57,7 +59,7 @@ If you close the prompt, open the `zcp` service in the dashboard. Its panel show
## 3. Open the workspace
-After authentication, continue into **Browser VS Code**. The workspace opens with files, ZCP configuration, terminal access, and the Claude Code panel.
+After authentication, continue into **Browser VS Code**. The workspace opens with files, ZCP configuration, terminal access, and your coding agent panel (the Claude Code panel in the screenshots below).
=18.0"
}
-}
\ No newline at end of file
+}
diff --git a/apps/docs/sidebars.js b/apps/docs/sidebars.js
index 74b62679a..b6c4ff87b 100644
--- a/apps/docs/sidebars.js
+++ b/apps/docs/sidebars.js
@@ -26,6 +26,25 @@ module.exports = {
},
className: 'homepage-sidebar-item',
},
+ {
+ type: 'category',
+ label: 'Quickstart',
+ link: {
+ type: 'doc',
+ id: 'quickstart/quickstart',
+ },
+ customProps: {
+ sidebar_icon: 'rocket-launch',
+ },
+ className: 'homepage-sidebar-item',
+ items: [
+ {
+ type: 'doc',
+ id: 'quickstart/quickstart-going-further',
+ label: 'Deploy Your First App',
+ },
+ ],
+ },
{
type: 'html',
value: 'Features',
@@ -486,7 +505,7 @@ module.exports = {
},
{
type: 'html',
- value: 'Zerops.yml',
+ value: 'Zerops.yaml',
customProps: {
sidebar_is_group_divider: true,
},
diff --git a/apps/docs/src/plugins/markdown-source/__tests__/permalink.test.js b/apps/docs/src/plugins/markdown-source/__tests__/permalink.test.js
new file mode 100644
index 000000000..12cf200c6
--- /dev/null
+++ b/apps/docs/src/plugins/markdown-source/__tests__/permalink.test.js
@@ -0,0 +1,67 @@
+'use strict';
+
+const test = require('node:test');
+const assert = require('node:assert/strict');
+const {
+ sourceToRelativePath,
+ normalizePermalinkKey,
+ permalinkToDestRelative,
+ buildPermalinkToSourceMap,
+} = require('../index');
+
+test('sourceToRelativePath strips @site/content/ prefix', () => {
+ assert.equal(
+ sourceToRelativePath('@site/content/quickstart/quickstart-going-further.mdx'),
+ 'quickstart/quickstart-going-further.mdx',
+ );
+});
+
+test('normalizePermalinkKey handles custom slug .md URLs', () => {
+ assert.equal(
+ normalizePermalinkKey('/quickstart/deploy-your-first-app.md'),
+ '/quickstart/deploy-your-first-app',
+ );
+ assert.equal(normalizePermalinkKey('/.md'), '/');
+ assert.equal(normalizePermalinkKey('/guides/backup/'), '/guides/backup');
+});
+
+test('permalinkToDestRelative maps homepage and nested paths', () => {
+ assert.equal(permalinkToDestRelative('/'), '.md');
+ assert.equal(
+ permalinkToDestRelative('/quickstart/deploy-your-first-app'),
+ 'quickstart/deploy-your-first-app.md',
+ );
+});
+
+test('buildPermalinkToSourceMap uses doc permalink, not file path', () => {
+ const map = buildPermalinkToSourceMap(
+ {
+ 'docusaurus-plugin-content-docs': {
+ default: {
+ loadedVersions: [
+ {
+ docs: [
+ {
+ permalink: '/quickstart/deploy-your-first-app',
+ source:
+ '@site/content/quickstart/quickstart-going-further.mdx',
+ },
+ {
+ permalink: '/quickstart/quickstart',
+ source: '@site/content/quickstart/quickstart.mdx',
+ },
+ ],
+ },
+ ],
+ },
+ },
+ },
+ '/',
+ );
+
+ assert.equal(
+ map['/quickstart/deploy-your-first-app'],
+ 'quickstart/quickstart-going-further.mdx',
+ );
+ assert.equal(map['/quickstart/quickstart'], 'quickstart/quickstart.mdx');
+});
diff --git a/apps/docs/src/plugins/markdown-source/index.js b/apps/docs/src/plugins/markdown-source/index.js
index f3213541a..a443757ea 100644
--- a/apps/docs/src/plugins/markdown-source/index.js
+++ b/apps/docs/src/plugins/markdown-source/index.js
@@ -610,6 +610,71 @@ function cleanMarkdownForDisplay(content, filepath, siteDir, docsDir) {
return content;
}
+/** @site/content/foo/bar.mdx → foo/bar.mdx */
+function sourceToRelativePath(source) {
+ return source.replace(/^@site\/content\//, '');
+}
+
+/** Normalize a URL path or permalink to a lookup key (e.g. /.md → /). */
+function normalizePermalinkKey(urlPath) {
+ let p = urlPath.split('?')[0].split('#')[0].replace(/\.md$/, '');
+ if (!p.startsWith('/')) {
+ p = `/${p}`;
+ }
+ if (p.length > 1 && p.endsWith('/')) {
+ p = p.slice(0, -1);
+ }
+ return p || '/';
+}
+
+/** Map permalink key to a relative path inside the build output. */
+function permalinkToDestRelative(permalink) {
+ if (permalink === '/') {
+ return '.md';
+ }
+ return `${permalink.slice(1)}.md`;
+}
+
+/** Build permalink → content-relative-path from the docs plugin. */
+function buildPermalinkToSourceMap(allContent, baseUrl) {
+ const map = {};
+ const docsInstances = allContent['docusaurus-plugin-content-docs'] ?? {};
+
+ for (const instanceContent of Object.values(docsInstances)) {
+ const loadedVersions = instanceContent?.loadedVersions ?? [];
+ for (const version of loadedVersions) {
+ for (const doc of version.docs) {
+ let permalink = doc.permalink;
+ if (baseUrl !== '/' && permalink.startsWith(baseUrl)) {
+ permalink = permalink.slice(baseUrl.length - 1) || '/';
+ }
+ const key = normalizePermalinkKey(permalink);
+ map[key] = sourceToRelativePath(doc.source);
+ }
+ }
+ }
+
+ return map;
+}
+
+async function writeCleanedMarkdownFile({
+ sourcePath,
+ relPath,
+ destPath,
+ siteDir,
+ docsDir,
+}) {
+ await fs.ensureDir(path.dirname(destPath));
+ const content = await fs.readFile(sourcePath, 'utf8');
+ const cleanedContent = cleanMarkdownForDisplay(
+ content,
+ relPath,
+ siteDir,
+ docsDir,
+ );
+ await fs.writeFile(destPath, cleanedContent, 'utf8');
+}
+
// Recursively find all markdown files in a directory
function findMarkdownFiles(dir, fileList = [], baseDir = dir) {
const files = fs.readdirSync(dir);
@@ -678,10 +743,22 @@ async function copyImageDirectories(docsDir, buildDir) {
module.exports = function markdownSourcePlugin(context, options) {
const docsDir = path.join(context.siteDir, 'content');
+ const { baseUrl } = context;
+ /** @type {Record} */
+ const permalinkToSource = {};
// Resolve a `.md` URL path back to a source file under content/.
// Returns the absolute path or null when no source exists.
function resolveSourcePath(urlPath) {
+ const permalink = normalizePermalinkKey(urlPath);
+ const mapped = permalinkToSource[permalink];
+ if (mapped) {
+ const mappedPath = path.join(docsDir, mapped);
+ if (fs.existsSync(mappedPath)) {
+ return mappedPath;
+ }
+ }
+
const stripped = urlPath.replace(/^\//, '').replace(/\.md$/, '');
const mdxCandidate = path.join(docsDir, `${stripped}.mdx`);
if (fs.existsSync(mdxCandidate)) return mdxCandidate;
@@ -693,6 +770,13 @@ module.exports = function markdownSourcePlugin(context, options) {
return {
name: 'markdown-source-plugin',
+ async allContentLoaded({ allContent }) {
+ Object.assign(
+ permalinkToSource,
+ buildPermalinkToSourceMap(allContent, baseUrl),
+ );
+ },
+
// Provide theme components from the plugin (eliminates need for manual copying)
getThemePath() {
return path.resolve(__dirname, './theme');
@@ -735,36 +819,64 @@ module.exports = function markdownSourcePlugin(context, options) {
},
async postBuild({ outDir }) {
- const docsDir = path.join(context.siteDir, 'content');
const buildDir = outDir;
console.log('[markdown-source-plugin] Copying markdown source files...');
- // Find all markdown files in docs directory
- const mdFiles = findMarkdownFiles(docsDir);
let copiedCount = 0;
+ const writtenSources = new Set();
+
+ for (const [permalink, relFile] of Object.entries(permalinkToSource)) {
+ const sourcePath = path.join(docsDir, relFile);
+ const destPath = path.join(
+ buildDir,
+ permalinkToDestRelative(permalink),
+ );
- // Process each markdown file to build directory
+ try {
+ if (!fs.existsSync(sourcePath)) {
+ console.warn(
+ `[markdown-source-plugin] Source not found for ${permalink}: ${relFile}`,
+ );
+ continue;
+ }
+
+ await writeCleanedMarkdownFile({
+ sourcePath,
+ relPath: relFile,
+ destPath,
+ siteDir: context.siteDir,
+ docsDir,
+ });
+ writtenSources.add(relFile);
+ copiedCount++;
+ console.log(
+ ` ✓ Processed: ${relFile} -> ${permalinkToDestRelative(permalink)}`,
+ );
+ } catch (error) {
+ console.error(` ✗ Failed to process ${relFile}:`, error.message);
+ }
+ }
+
+ const mdFiles = findMarkdownFiles(docsDir);
for (const mdFile of mdFiles) {
+ if (writtenSources.has(mdFile)) {
+ continue;
+ }
+
const sourcePath = path.join(docsDir, mdFile);
- // Convert .mdx to .md for the destination
const destFile = mdFile.replace(/\.mdx$/, '.md');
const destPath = path.join(buildDir, destFile);
try {
- // Ensure destination directory exists
- await fs.ensureDir(path.dirname(destPath));
-
- // Read the markdown file
- const content = await fs.readFile(sourcePath, 'utf8');
-
- // Pass siteDir and docsDir for import resolution
- const cleanedContent = cleanMarkdownForDisplay(content, mdFile, context.siteDir, docsDir);
-
- // Write the cleaned content
- await fs.writeFile(destPath, cleanedContent, 'utf8');
+ await writeCleanedMarkdownFile({
+ sourcePath,
+ relPath: mdFile,
+ destPath,
+ siteDir: context.siteDir,
+ docsDir,
+ });
copiedCount++;
-
console.log(` ✓ Processed: ${mdFile} -> ${destFile}`);
} catch (error) {
console.error(` ✗ Failed to process ${mdFile}:`, error.message);
@@ -779,4 +891,9 @@ module.exports = function markdownSourcePlugin(context, options) {
console.log(`[markdown-source-plugin] Successfully copied ${imgDirCount} image directories`);
},
};
-};
\ No newline at end of file
+};
+
+module.exports.sourceToRelativePath = sourceToRelativePath;
+module.exports.normalizePermalinkKey = normalizePermalinkKey;
+module.exports.permalinkToDestRelative = permalinkToDestRelative;
+module.exports.buildPermalinkToSourceMap = buildPermalinkToSourceMap;
\ No newline at end of file
diff --git a/apps/docs/src/theme/DocItem/Content/index.tsx b/apps/docs/src/theme/DocItem/Content/index.tsx
index 63446e91f..3f9217307 100644
--- a/apps/docs/src/theme/DocItem/Content/index.tsx
+++ b/apps/docs/src/theme/DocItem/Content/index.tsx
@@ -8,6 +8,7 @@ import type { Props } from '@theme/DocItem/Content';
import { DocContextValue } from '@medusajs/docs';
import { Badge, BadgeVariant } from 'docs-ui';
import Head from '@docusaurus/Head';
+import { useLocation } from '@docusaurus/router';
/**
Title can be declared inside md content or declared through
@@ -34,6 +35,10 @@ export default function DocItemContent({ children }: Props): JSX.Element {
frontMatter: { badge, description, image },
metadata,
} = useDoc() as DocContextValue;
+ const location = useLocation();
+ const ogImage =
+ image ??
+ `https://docs.zerops.io/og?path=${encodeURIComponent(location.pathname)}`;
const syntheticTitle = useSyntheticTitle();
return (
@@ -41,14 +46,14 @@ export default function DocItemContent({ children }: Props): JSX.Element {
{metadata.title}
{description && }
-
+
-
+
diff --git a/apps/docs/src/theme/Tabs/index.tsx b/apps/docs/src/theme/Tabs/index.tsx
index 1b78a0807..fee6de871 100644
--- a/apps/docs/src/theme/Tabs/index.tsx
+++ b/apps/docs/src/theme/Tabs/index.tsx
@@ -172,11 +172,11 @@ function TabList({
],
!isCodeTabs && [
'[&:not(:last-child)]:mr-0.5 px-0.75 py-[6px] txt-compact-small-plus',
- 'border-0 rounded-full transition-shadow duration-200 ease-ease',
+ 'rounded-full border border-solid transition-all duration-200 ease-ease',
selectedValue === value &&
- 'text-medusa-fg-base shadow-card-rest dark:shadow-card-rest-dark',
+ 'text-medusa-fg-base border-[#36CBB8] bg-medusa-bg-base shadow-card-rest dark:shadow-card-rest-dark',
selectedValue !== value &&
- 'text-medusa-fg-subtle hover:text-medusa-fg-base',
+ 'text-medusa-fg-subtle border-medusa-border-base bg-medusa-bg-subtle hover:text-medusa-fg-base hover:bg-medusa-bg-subtle-hover',
'flex gap-0.5',
],
'!mt-0 cursor-pointer',
diff --git a/apps/docs/static/img/screenshots/pipeline-running-dashboard.png b/apps/docs/static/img/screenshots/pipeline-running-dashboard.png
new file mode 100644
index 000000000..18a2adf5b
Binary files /dev/null and b/apps/docs/static/img/screenshots/pipeline-running-dashboard.png differ
diff --git a/apps/docs/static/img/screenshots/project-services-overview.png b/apps/docs/static/img/screenshots/project-services-overview.png
new file mode 100644
index 000000000..c8a07714c
Binary files /dev/null and b/apps/docs/static/img/screenshots/project-services-overview.png differ
diff --git a/apps/docs/static/img/screenshots/recipe-predeploy-breakdown.png b/apps/docs/static/img/screenshots/recipe-predeploy-breakdown.png
new file mode 100644
index 000000000..cf2735523
Binary files /dev/null and b/apps/docs/static/img/screenshots/recipe-predeploy-breakdown.png differ
diff --git a/apps/docs/static/llms-full.txt b/apps/docs/static/llms-full.txt
index 5bb32a4af..b6be83ccc 100644
--- a/apps/docs/static/llms-full.txt
+++ b/apps/docs/static/llms-full.txt
@@ -9378,7 +9378,7 @@ Most coding-agent platforms went agent-first, then bolted on infrastructure —
### Your agent, your subscription
-Bring whichever agent you already use. Claude Code today; Codex, Gemini CLI, opencode, and any MCP-capable client next. The container is a regular Ubuntu — install your own CLI tools, drop in your `.claude` / `.cursor` configs, attach your IDE over SSH. **Zerops doesn't resell tokens or proxy your model calls** — sign in with your own Anthropic / OpenAI / Google subscription and the agent talks to its provider directly.
+ZCP supports multiple coding agents including Claude Code (Anthropic), Codex (OpenAI), Antigravity, and Grok Build. The container is a regular Ubuntu — install your own CLI tools, drop in your `.claude` / `.cursor` configs, attach your IDE over SSH. **Zerops doesn't resell tokens or proxy your model calls** — sign in with your own Anthropic / OpenAI / Google subscription and the agent talks to its provider directly.
### An ordinary Zerops project underneath
@@ -9396,7 +9396,7 @@ Runtimes for Bun, Deno, Node.js, Go, Python, Rust, Java, .NET, PHP, Elixir, Glea
The agent reaches your project's private network one of two ways:
-- **Remote** — a `zcp` service deployed into the project runs the agent. You attach to it with Claude Code's IDE extension, with any IDE that supports remote development (Cursor, Windsurf, VS Code Remote), or by running [`zcli vpn up`](/references/networking/vpn) and ssh-ing into `zcp` to drive the rest of the project from a shell.
+- **Remote** — a `zcp` service deployed into the project runs the agent. You attach to it with your agent's IDE extension or terminal, with any IDE that supports remote development (Cursor, Windsurf, VS Code Remote), or by running [`zcli vpn up`](/references/networking/vpn) and ssh-ing into `zcp` to drive the rest of the project from a shell.
- **Local** — install the `zcp` MCP on your machine and run `zcli vpn up` to join the network. From there your IDE, agent, and shell can ssh directly into any container.
Either way, the agent reaches [managed services by hostname](/references/networking/internal-access) (`db:5432`, `cache:6379`), deploys through the [Zerops pipeline](/features/pipeline), and reads logs and events the same way you would.
@@ -9534,47 +9534,47 @@ With the model clear, here's where ZCP sits among adjacent tools. People say "ag
_AWS MCP servers · Railway MCP · Fly.io MCP · Render MCP_
-Most major PaaS providers have shipped an MCP — provision services, deploy code, list resources, read operational state. Great for "let my agent ship to my Railway account." These are *deploy and operate* surfaces, driven from outside the platform — and they reflect what's underneath: platforms optimized for day-one deploy that tuck the infrastructure behind a wall. Once an agent needs to actually *develop* against that infrastructure — debug a failed health check, follow real logs, hit Postgres from inside the network, inspect what a build is doing, run the dev loop before it ships anything — the wall stops it. That's by design on those platforms, not a missing feature.
+Most major PaaS providers have shipped an MCP — provision services, deploy code, list resources, read operational state. Great for "let my agent ship to my Railway account." These are *deploy and operate* surfaces, driven from outside the platform — and they reflect what's underneath: platforms optimized for day-one deploy that tuck the infrastructure behind a wall. Log and metric read tools landed across the category in 2025 (and AWS only just hit GA), but the **in-network, in-container** surface an agent needs to actually *develop* — hit Postgres from inside the network, follow a build live, drive the dev loop before it ships anything — is still on the other side of the wall.
#### Cloud VPS MCPs
_Hetzner Cloud MCP · DigitalOcean MCP · Linode MCP · raw SSH/server MCPs_
-"Let your agent manage your Hetzner VPS." An MCP gives the agent access to a Linux box — provision it, SSH in, install Docker and Postgres and nginx, set up systemd units, point a domain at it. Maximum control, lowest cost, full Linux to play with. The same reason senior developers reach for managed platforms applies here: even if you *can* harden SSH, write nginx configs, tune `pg_hba.conf`, rotate TLS, set firewall rules, run fail2ban, and stay on top of CVEs across kernel, OpenSSL, Docker, Postgres, and nginx — you usually don't want to. Each layer is its own domain with its own gotchas, each is a security surface that drifts the moment you stop tending it, and every project becomes a snowflake. Hand that work to an agent and you also hand it the blast radius: misconfigured firewall, debug endpoint left open, port 5432 exposed to the internet, keys never rotated. ZCP is the inverse trade-off — the **guardrails** of a managed platform. Private networking, TLS, isolated services, safe defaults, managed backups, no exposed ports unless you opt in — all built in. The agent operates through [project-scoped MCP tools](/zcp/reference/mcp-operations) instead of `sudo` on a fresh Ubuntu box, so the mistakes that matter on a VPS aren't reachable from where it sits.
+"Let your agent manage your Hetzner VPS." Two shapes cluster here: vendor-API MCPs (DigitalOcean ships an official one) that provision services from outside the box, and community-built SSH MCPs (Hetzner, Linode, Vultr) that give the agent shell access — provision it, SSH in, install Docker and Postgres and nginx, set up systemd units, point a domain at it. Maximum control, lowest cost, full Linux to play with. The same reason senior developers reach for managed platforms applies here: even if you *can* harden SSH, write nginx configs, tune `pg_hba.conf`, rotate TLS, set firewall rules, run fail2ban, and stay on top of CVEs across kernel, OpenSSL, Docker, Postgres, and nginx — you usually don't want to. Each layer is its own domain with its own gotchas, each is a security surface that drifts the moment you stop tending it, and every project becomes a snowflake. Hand that work to an agent and you also hand it the blast radius: misconfigured firewall, debug endpoint left open, port 5432 exposed to the internet, keys never rotated. ZCP is the inverse trade-off — the **guardrails** of a managed platform. Private networking, TLS, isolated services, safe defaults, managed backups, no exposed ports unless you opt in — all built in. The agent operates through [project-scoped MCP tools](/zcp/reference/mcp-operations) instead of `sudo` on a fresh Ubuntu box, so the mistakes that matter on a VPS aren't reachable from where it sits.
#### Cloud dev environments with AI
-_GitHub Codespaces + Copilot Workspace · Gitpod · Coder_
+_GitHub Codespaces + Copilot Coding Agent · Ona (ex-Gitpod) · Coder_
-A managed Linux container in the cloud with your editor and an AI assistant attached. Solves "where the agent runs" so state survives between sessions and machine setup stops being a question. The `zcp` service is the closest thing in this category — managed Linux container, Cloud IDE, your agent of choice — except it lives *inside* a Zerops project, addressing the project's runtimes, database, and cache by hostname, with deploys and logs as primitives the agent can call.
+A managed Linux container in the cloud with your editor and an AI assistant attached. Solves "where the agent runs" so state survives between sessions and machine setup stops being a question. The category itself is repositioning toward **governed agent runtimes** — Copilot Coding Agent (the productized successor to Workspace), Coder Agents, and Ona (Gitpod's rebrand after it shut down the SaaS in late 2025) all point the same way. The `zcp` service is the closest thing in this category — managed Linux container, Cloud IDE, your agent of choice — except it lives *inside* a Zerops project, addressing the project's runtimes, database, and cache by hostname, with deploys and logs as primitives the agent can call.
#### Bundled agent platforms
-_Replit Agent · Lovable · Bolt.new · v0 · Devin · OpenHands_
+_Replit Agent · Lovable · Bolt.new · v0 · Devin_
-The agent, the workspace, the stack, and (often) the hosting target are fused into one closed product. Fast for prototypes. Decisions are made for you. Switching agents usually means switching platforms, and production-grade primitives — a real dev/stage/prod release flow, private networking, observability — tend to be limited or absent. **ZCP doesn't bundle**: the agent and model stay yours on your own subscription, and the platform underneath is normal Zerops with the full stack of managed services, networking, deploys, and observability.
+The agent, the workspace, the stack, and (often) the hosting target are fused into one closed product. Fast for prototypes. Decisions are made for you. Switching agents usually means switching platforms, and production-grade primitives — a real dev/stage/prod release flow, private networking, observability — are **uneven** across this category: v0, Bolt, and Devin have moved upmarket with deploy/auth/DB primitives, others have not. **ZCP doesn't bundle**: the agent and model stay yours on your own subscription, and the platform underneath is normal Zerops with the full stack of managed services, networking, deploys, and observability.
#### Local coding agents
-_Cursor · Windsurf · Zed · Claude Code · Codex CLI · Aider · Cline_
+_Cursor · Windsurf · Zed · Claude Code · Codex · Antigravity · Grok Build · Aider · Cline_
-The agent runs on your machine, edits your local checkout, runs local commands. Excellent at code changes. Anything beyond your machine — databases, networking, deploy targets, runtime logs — is yours to wire in. Install the ZCP MCP locally and run `zcli vpn up`, and any of these agents can now reach a real Zerops project alongside your local code: services addressed by hostname, deploys, logs, events.
+The agent runs on your machine, edits your local checkout, runs local commands. Excellent at code changes. **MCP** is now native across these tools, so external reach — databases, networking, deploy targets, runtime logs — comes through plugins instead of bare hands. The agent still lives on your laptop, though: anything off-machine has to be reached, not *inhabited*. Install the ZCP MCP locally and run `zcli vpn up`, and any of these agents can now reach a real Zerops project alongside your local code: services addressed by hostname, deploys, logs, events.
#### Code-execution sandboxes
_E2B · Modal · Daytona · CodeSandbox SDK_
-Ephemeral Linux environments that AI *applications* spin up — often per request — to execute generated code safely. The right primitive when you're building a product that needs a model to run untrusted code and hand back the output. They're a building block for AI applications, not somewhere a coding agent settles in to iterate on your project. Different shape from ZCP; they show up here because the names cluster nearby.
+Mostly ephemeral Linux environments that AI *applications* spin up — often per request — to execute generated code safely (E2B, Modal). The right primitive when you're building a product that needs a model to run untrusted code and hand back the output. Some have pivoted toward **stateful, resumable agent workspaces** — Daytona now explicitly markets "every agent a computer," and CodeSandbox SDK's hibernation/resume sits between ephemeral and persistent. Still a different shape from ZCP; they show up here because the names cluster nearby.
#### Agent SDKs and frameworks
-_Cloudflare Agents · Vercel AI SDK · Mastra · Anthropic Agent SDK_
+_Cloudflare Agents · Vercel AI SDK · Mastra · Claude Agent SDK_
Libraries for building and shipping agents to *your* users — tool calling, memory, orchestration, model providers, sometimes hosting. They're how somebody would build a product like ZCP, not where a coding agent runs against a project. Same disambiguation — adjacent on the shelf, different shape.
## Where to start
-- [Quickstart](/zcp/quickstart) — AI Agent recipe, Claude Code, and a real product change in about five minutes.
+- [Quickstart](/zcp/quickstart) — AI Agent recipe, bundled coding agent, and a real product change in about five minutes.
- [ZCP MCP overview](/zcp/overview) — What the `zcp` MCP gives the agent, where it runs, and how a run ends in proof or a blocker.
- [Remote or local setup](/zcp/setup/choose-workspace) — Choose where the `zcp` MCP runs — inside Zerops with bundled tools, or beside your local editor.
- [Build and ship](/zcp/workflows/build-with-zcp) — Runtime layout, development, delivery, packaging, and production release.
@@ -10652,9 +10652,9 @@ In **Pipelines & CI/CD settings** section of your service detail:
- **Re-deploy last pipeline** - With optional secret env variable updates
- **Trigger new pipeline** - From git repo or with custom configuration
-#### Using import YAML
+#### Using Import YAML
-Add `buildFromGit: ` to your service configuration for one-time build during import. See [import documentation](/references/import#service-basic-configuration).
+Add `buildFromGit: ` to your service configuration for one-time build during import. See [Import YAML documentation](/references/import#service-basic-configuration).
## Build phase
@@ -15458,7 +15458,7 @@ When using SSHFS (`zerops_mount`) for dev workflows, deploy replaces the contain
# Guides > Environment Variables
-Zerops manages environment variables at two scopes (project and service) with strict build/runtime isolation. Variables are set via zerops.yml, import.yml, or GUI. **Both project-level vars AND cross-service vars (`${hostname_varname}`) auto-inject as OS env vars into every container in the project** — no declaration required. `run.envVariables` exists only for mode flags and framework-convention renames. Re-declaring an auto-injected var under its own name creates a literal-string self-shadow. Secret vars are write-only after creation. Changes require service restart.
+Zerops manages environment variables at two scopes (project and service) with strict build/runtime isolation. Variables are set via zerops.yml, import.yml, or GUI. **Project vars auto-inherit into every service** — read them directly, no declaration. **Cross-service (sibling) vars do NOT auto-inject under the default `envIsolation=service`** — reference a sibling's value explicitly as `${hostname_varname}` in `run.envVariables` (only legacy `none` mode injects siblings as bare vars). Secret reads are privilege-gated (an admin token returns the value; a read-only token gets `REDACTED`). A running process keeps its boot-time env — restart it (not reload) to pick up a changed value.
---
@@ -15466,21 +15466,21 @@ Zerops manages environment variables at two scopes (project and service) with st
| Scope | Defined In | Visibility | Editable Without Redeploy |
|-------|-----------|------------|--------------------------|
-| **Project** | import.yml `project.envVariables`, GUI | All services (auto-inherited) | Yes (restart required) |
-| **Service secret** | import.yml `envSecrets`, GUI | Single service | Yes (restart required) |
+| **Project** | import.yml `project.envVariables`, GUI | All services (auto-inherited) | Yes (restart to apply) |
+| **Service secret** | import.yml `envSecrets`, GUI | Single service | Yes (restart to apply) |
| **Service basic (build)** | zerops.yml `build.envVariables` | Build container only | No (redeploy required) |
| **Service basic (runtime)** | zerops.yml `run.envVariables` | Runtime container only | No (redeploy required) |
| **Service basic (runtime)** | zerops.yml `run.envVariables` | Runtime container only | No (redeploy required) |
## Variable Precedence
-When the same key exists at multiple levels:
+Total order for the bare key (highest wins): **system/platform > yaml-baked `run.envVariables` > service secret/userData > project**.
-1. **Service basic (build/runtime)** wins over service secret
-2. **Service-level** wins over project-level
-3. Build and runtime are **separate environments** -- same key can have different values in each
+1. **yaml-baked `run.envVariables` owns its key** — a service secret/userData set on the same key is **rejected** (`userDataDuplicateKey`); the two never coexist. To change a yaml-baked value, edit `zerops.yml` and redeploy.
+2. **Service-level** wins over **project-level**.
+3. Build and runtime are **separate environments** -- same key can have different values in each.
-**DO NOT** create a secret and a basic runtime variable with the same key expecting both to persist. The basic runtime variable from zerops.yml silently overrides the secret.
+**DO NOT** set a secret/service var on a key already declared in `run.envVariables` — the platform rejects it. The yaml var owns the key; edit the yaml and redeploy instead.
## Build/Runtime Isolation
@@ -15503,104 +15503,62 @@ zerops:
API_KEY: "12345-abcde"
```
-## Cross-Service References — Auto-Injected Project-Wide
+## Cross-Service References — Explicit `${hostname_varname}` Required
-**Every service's variables are automatically injected as OS environment variables into every other service's containers** — both runtime and build. A worker container sees `db_hostname`, `db_password`, `queue_user`, `storage_apiUrl`, etc. as real OS env vars at container start. Zero declaration in zerops.yml required.
-
-Read them directly in application code:
-
-```javascript
-// Node — lowercase native names match the platform
-const host = process.env.db_hostname;
-const pwd = process.env.db_password;
-const natsUser = process.env.queue_user;
-```
-
-```php
-// PHP
-$host = getenv('db_hostname');
-```
-
-`run.envVariables` and `build.envVariables` have **two legitimate uses only**:
-
-1. **Mode flags** — per-setup values that don't come from another service:
- ```yaml
- run:
- envVariables:
- NODE_ENV: production
- APP_ENV: local
- ```
-
-2. **Framework-convention renames** — forward a platform var under a different name because the framework config expects it. The key on the left MUST DIFFER from the source var name on the right:
- ```yaml
- run:
- envVariables:
- DB_HOST: ${db_hostname} # TypeORM expects uppercase DB_HOST
- DATABASE_URL: ${db_connectionString}
- ```
-
-**Do NOT re-declare auto-injected vars under their own name.** It is always wrong and never useful:
+Under the default `envIsolation=service`, a service does **NOT** automatically see another service's variables — **not even a managed database's connection vars**. To use a sibling's value, reference it explicitly in `run.envVariables`; the left-hand key is the name your app reads, the right-hand `${hostname_varname}` is the source:
```yaml
run:
envVariables:
- db_hostname: ${db_hostname} # SELF-SHADOW — see next section
- db_password: ${db_password} # SELF-SHADOW
- queue_hostname: ${queue_hostname} # SELF-SHADOW
- API_URL: ${API_URL} # SELF-SHADOW (project-level variant)
+ DB_HOST: ${db_hostname}
+ DB_PASS: ${db_password}
+ DATABASE_URL: ${db_connectionString}
+ CACHE_URL: ${cache_connectionString}
```
-The referenced variable does **not** need to exist at definition time — Zerops resolves at container start.
-
-### Self-Shadow Trap
-
-Writing `varname: ${varname}` in `run.envVariables` creates a literal-string self-shadow. The platform's interpolator sees the service-level variable of that name first, can't recurse back to the auto-injected value, and the resolved OS env var becomes the literal string `${varname}`:
-
-```yaml
-run:
- envVariables:
- db_hostname: ${db_hostname} # OS env: db_hostname='${db_hostname}' (literal)
- db_password: ${db_password} # OS env: db_password='${db_password}' (literal)
+```javascript
+// App reads the names you mapped above:
+const host = process.env.DB_HOST;
```
-At runtime, the worker tries to connect to `"${db_hostname}:5432"` and crashes. The fix is to **delete the entire block** — those vars are already in the container's env without any declaration.
-
-This applies identically to project-level vars (`${API_URL}`, `${APP_SECRET}`) and cross-service vars (`${db_hostname}`, `${queue_user}`) — both auto-propagate, both self-shadow under the same rule.
+- The reference **resolves at container start**, independent of isolation mode — the referenced var does not need to exist at definition time.
+- An **unresolved ref stays literal** (`${db_hostname}` reaches the process verbatim) — no error, no blank. A wrong hostname/var on the right-hand side becomes a literal string and the app fails at connect time.
+- **Hostname transformation**: dashes become underscores. Service `my-db` variable `port` is `${my_db_port}`.
-**Hostname transformation**: dashes become underscores. Service `my-db` variable `port` is `${my_db_port}`.
+Only legacy `envIsolation=none` auto-injects every sibling's vars as bare `_KEY` OS env vars without a ref — see Isolation Modes. New projects are `service`; rely on explicit refs.
### Cross-Service References in API vs Runtime
-Cross-service references (`${hostname_varname}`) are **resolved at container start time**, not at definition time. This means:
+Cross-service references (`${hostname_varname}`) are **resolved at container start time**, not at definition time:
-- **`zerops_discover` with `includeEnvs=true`** returns the **literal template** (e.g., `${db_password}`), NOT the resolved value. This is expected — the API stores templates, not resolved values.
+- **`zerops_discover` with `includeEnvs=true`** returns the **literal template** (e.g., `${db_password}`), NOT the resolved value. The service-env API stores templates, not resolved values, and returns only the service's own user-set + intrinsic vars — yaml-baked `run.envVariables` come from the app-version, project vars from the project scope. Assemble across scopes (or read in-container) for the effective env.
- **Inside the running container**, environment variables contain the actual resolved values.
-- **Restarting a service does NOT change** what `zerops_discover` returns — it always shows templates. To verify resolved values, check from inside the container (e.g., via SSH or application endpoint).
+- **Restarting a service does NOT change** what `zerops_discover` returns — it always shows templates. To verify resolved values, check from inside the container.
### Isolation Modes (envIsolation)
-`envIsolation` does NOT control whether cross-service vars auto-inject — they do, in every mode. It controls something narrower: how `${hostname_varname}` templates inside zerops.yml and import.yml *resolve* during platform interpolation.
+`envIsolation` is a project-scope setting that controls whether sibling-service vars are auto-injected.
| Mode | Behavior |
|------|----------|
-| `service` (default) | Service-scoped: `${hostname_varname}` templates inside that service's YAML resolve by following the hostname prefix. The OS env in every container still contains every other service's vars as auto-injected keys. |
-| `none` (legacy) | Cross-service references can be written without the `${hostname_varname}` prefix (e.g. `${password}` resolves to the nearest match). Do not use for new projects — ambiguous, error-prone. |
-| `none` (legacy) | Cross-service references can be written without the `${hostname_varname}` prefix (e.g. `${password}` resolves to the nearest match). Do not use for new projects — ambiguous, error-prone. |
+| `service` (default) | **Siblings are isolated.** A service sees only its own vars + project vars + the explicit `${hostname_varname}` refs it declares in `run.envVariables`. Managed-service connection vars also require an explicit ref. |
+| `none` (legacy) | Every service's vars are auto-injected into every other container as bare `_KEY` OS env vars (source-side, directional). Ambiguous and broad — avoid for new projects. |
+| `none` (legacy) | Every service's vars are auto-injected into every other container as bare `_KEY` OS env vars (source-side, directional). Ambiguous and broad — avoid for new projects. |
Set in import.yml at project or service level:
```yaml
project:
- envIsolation: none # legacy — avoid
+ envIsolation: none # legacy — avoid; default is service
services:
- hostname: db
- envIsolation: none # legacy — avoid
+ envIsolation: none # per-service: expose THIS service's vars to siblings
```
-**Default (`service`) is the right choice.** The auto-inject behavior above applies under the default.
+**Default (`service`) is the right choice.** Wire cross-service explicitly with `${hostname_varname}` — it works in both modes, so code stays correct if isolation ever changes.
## Project Variables -- Auto-Inherited
-Project variables are **automatically available in every service, in both runtime AND build containers**. The platform injects them as OS env vars at container start in every service's runtime container and also in every service's build container during the build phase. From zerops.yaml's point of view they are referenced **directly by name** with `${VAR_NAME}` — **no `RUNTIME_` prefix in either scope**. The `RUNTIME_` prefix is reserved for a different use case: lifting a single service's service-level runtime variable into that same service's build context. Project-scope vars are broader than service-scope and do not need lifting.
+Project variables are **automatically available in every service, in both runtime AND build containers** — injected as OS env vars at container start. From application code, read them directly (`process.env.API_URL`). From zerops.yaml, reference them by name with `${VAR_NAME}` — **no `RUNTIME_` prefix** (that prefix is only for lifting a service's own runtime var into its build context).
**In shell commands** (buildCommands, initCommands, start) project vars are directly readable:
```yaml
@@ -15610,42 +15568,42 @@ build:
- VITE_API_URL=$API_URL npm run build # or pass it forward by shell prefix
```
-**In `build.envVariables` YAML** (to compose a derived var that the bundler consumes) reference the project var directly without prefix:
+**In `build.envVariables` / `run.envVariables` YAML** (to forward a project var under a framework-conventional name) reference it directly without prefix:
```yaml
build:
envVariables:
- VITE_API_URL: ${API_URL} # project var API_URL read as-is, NO RUNTIME_ prefix
+ VITE_API_URL: ${API_URL} # project var API_URL read as-is
+run:
+ envVariables:
+ CORS_ALLOWED_ORIGIN: ${FRONTEND_URL} # forwarded under a different name
```
-**In `run.envVariables` YAML** (to forward a project var under a framework-conventional name without creating a shadow), reference directly without prefix:
+To **override** a project variable for one service, define a service-level variable with the same key and a DIFFERENT VALUE (not a reference to the project var):
```yaml
run:
envVariables:
- CORS_ALLOWED_ORIGIN: ${FRONTEND_URL} # project var FRONTEND_URL forwarded under a different name
+ LOG_LEVEL: debug # overrides project-level LOG_LEVEL for this service
```
-**DO NOT** re-reference an auto-injected variable under its SAME name — that's a self-shadow loop. Applies to BOTH project-level vars AND cross-service vars:
+### Self-Shadow Trap — same name on both sides
-```yaml
-envVariables:
- PROJECT_NAME: ${PROJECT_NAME} # project-level self-shadow
- API_URL: ${API_URL} # project-level self-shadow
- db_hostname: ${db_hostname} # cross-service self-shadow
- queue_user: ${queue_user} # cross-service self-shadow
-```
+Writing `varname: ${varname}` (the left key identical to the source on the right) is always wrong:
-All four resolve to the literal string `${VAR_NAME}` inside the container — the framework tries to connect to `"${db_hostname}:5432"` and crashes. The fix is to delete those lines entirely — the platform already injects the real value as an OS env var.
-
-To **override** a project variable for one service, define a service-level variable with the same key and a DIFFERENT VALUE (not a reference to the project var):
```yaml
run:
envVariables:
- LOG_LEVEL: debug # overrides project-level LOG_LEVEL for this service
+ API_URL: ${API_URL} # project-level self-shadow
+ db_hostname: ${db_hostname} # cross-service self-shadow
```
+The interpolator sees the service-level variable of that name first, can't recurse back to the inherited/referenced value, and the OS env var resolves to the literal string `${varname}` — the app then connects to `"${db_hostname}:5432"` and crashes.
+
+- For a **project var** you only want to read: delete the line — it already auto-inherits.
+- For a **cross-service** value: use a **different** left-hand name (`DB_HOST: ${db_hostname}`), never the same name.
+
### Typical pattern: project-level URL constants for dual-runtime recipes
-Dual-runtime recipes (frontend SPA + backend API on the same platform) use project-level URL constants as the single source of truth for cross-service URLs. The constants are derived from `${zeropsSubdomainHost}` (a platform-generated project-scope env var present from project creation) and the services' known hostnames:
+Dual-runtime recipes (frontend SPA + backend API) use project-level URL constants as the single source of truth for cross-service URLs, derived from `${zeropsSubdomainHost}` (a platform-generated project-scope var present from project creation):
```yaml
project:
@@ -15654,14 +15612,14 @@ project:
FRONTEND_URL: https://appstage-${zeropsSubdomainHost}.prg1.zerops.app
```
-The platform resolves `${zeropsSubdomainHost}` when injecting the value into services at container start. The frontend consumes `API_URL` via plain `${API_URL}` in `build.envVariables` (baking it into the bundle at compile time) — **no `RUNTIME_` prefix**. The API consumes `FRONTEND_URL` via plain `${FRONTEND_URL}` in `run.envVariables` (for CORS allow-list). The same names must be set on the workspace project via `zerops_env project=true action=set` after provision, so workspace verification doesn't see literal `${FRONTEND_URL}` strings.
+The frontend consumes `API_URL` via plain `${API_URL}` in `build.envVariables` (baked into the bundle at compile time). The API consumes `FRONTEND_URL` via plain `${FRONTEND_URL}` in `run.envVariables` (CORS allow-list). Set the same names on the workspace project via `zerops_env project=true action=set` after provision.
## Secret Variables
- Defined via GUI, import.yml `envSecrets`, or `dotEnvSecrets`
-- **Write-only after creation** -- values masked in GUI, cannot be read back via API
-- Can be updated without redeploy, but service **must be restarted**
-- Overridden by basic (zerops.yml) variables with the same key
+- **Read is privilege-gated** -- masked in GUI; via API an admin/write token returns the value verbatim, a read-only token returns `REDACTED` (keyed on `sensitive=true`). In-container the value is plaintext (the app needs it). Project-level `sensitive=true` does NOT persist — only service-level is a true secret surface.
+- Can be updated without redeploy, but the service **must be restarted** to pick it up.
+- Overridden by yaml-baked `run.envVariables` with the same key (yaml owns the key).
### dotEnvSecrets
@@ -15704,22 +15662,22 @@ run:
## Restart Requirement
-Env var changes (secret or project) take effect only on container start. The running process does **not** receive updated values.
+An env-store change (secret or project) propagates to the container in ~5–10s without a redeploy, but the **running process keeps its boot-time environ** — only newly-spawned processes see it.
-**DO NOT** expect hot-reload of env vars. After changing secrets or project vars in GUI, **restart the service**. For zerops.yml `envVariables` changes, a **full redeploy** is required.
+**DO NOT** expect hot-reload of env vars. After changing secrets or project vars, **restart the service** (not reload — reload does not re-read env for the running process; PHP-FPM keeps its boot config). For `zerops.yml` `run.envVariables` changes, a **full redeploy** is required (they are baked into the app version).
## System-Generated Variables
-Zerops auto-generates variables per service (e.g., `hostname`, `PATH`, DB connection strings). Cannot be deleted. Some read-only (`hostname`), others editable (`PATH`). Can be referenced by other services using `${hostname_varname}`.
+Zerops auto-generates variables per service (e.g., `hostname`, `PATH`, DB connection strings). Cannot be deleted. Some read-only (`hostname`), others editable (`PATH`). Reference them from another service with an explicit `${hostname_varname}`.
## Common Mistakes
-- **DO NOT** re-reference auto-injected vars under their own name — self-shadow loop. Applies to BOTH project-level (`API_URL: ${API_URL}`) AND cross-service (`db_hostname: ${db_hostname}`, `queue_user: ${queue_user}`).
-- **DO NOT** declare cross-service vars you only want to READ — they are already in the container's OS env. Read via `process.env.db_hostname` / `getenv('db_hostname')` directly. Declare in `run.envVariables` only to RENAME (e.g. `DB_HOST: ${db_hostname}`) or to set mode flags.
-- **DO NOT** forget restart after GUI/API env changes — process won't see new values
-- **DO NOT** expect `envReplace` to recurse subdirectories — it does not
-- **DO NOT** rely on reading secret values back — they are write-only after creation
-- **DO NOT** create both secret and basic vars with same key — basic silently wins
+- **DO NOT** expect a sibling's vars to appear automatically under default `service` isolation — reference them explicitly as `${hostname_varname}` in `run.envVariables` (the bare `_KEY` injected form is `none`-only legacy).
+- **DO NOT** re-reference a var under its SAME name -- self-shadow loop. Project vars auto-inherit (read directly); cross-service uses a DIFFERENT left-hand name (`DB_HOST: ${db_hostname}`).
+- **DO NOT** set a secret/service var on a key already in `run.envVariables` -- rejected (`userDataDuplicateKey`); the yaml owns the key, edit yaml + redeploy.
+- **DO NOT** assume secret values are unreadable -- API read is privilege-gated (admin verbatim, read-only `REDACTED`), not unconditionally write-only.
+- **DO NOT** forget restart after GUI/API env changes -- the running process won't see new values.
+- **DO NOT** expect `envReplace` to recurse subdirectories -- it does not.
----------------------------------------
@@ -15927,7 +15885,7 @@ http://postgres:5432
- Service discovery is automatic — no manual network config
- VPN uses same hostnames: `http://api:3000` from local machine (both `api` and `api.zerops` resolve — VPN sets up DNS search domain)
-**Cross-service env vars**: prefix with hostname — e.g., `app_API_TOKEN`. Zerops auto-generates connection vars for managed services.
+**Cross-service env vars**: under the default `envIsolation=service`, reference a sibling's var explicitly as `${hostname_varname}` in `run.envVariables` (e.g. `${app_API_TOKEN}`) — siblings are NOT auto-injected. The bare `_KEY` injected form only appears under legacy `envIsolation=none`. Zerops auto-generates connection vars for managed services — reference them the same way (`${db_*}`).
**DO NOT** use `https://` for service-to-service calls — SSL terminates at the L7 balancer, internal network is already isolated.
@@ -16508,7 +16466,7 @@ Zerops offers three public access methods: zerops.app subdomains (dev only, 50MB
- **Not for production** — use for development/testing only
- Auto-provisioned SSL
- Pre-configure via import YAML: `enableSubdomainAccess: true` (works for all runtime/web types)
-- **Activate routing via API:** `zerops_subdomain enable` (only works on deployed/ACTIVE services) — call once after the first deploy of each new service, even if `enableSubdomainAccess: true` was set in import. Import pre-configures routing but does NOT activate L7 balancer; without the explicit enable call, the subdomain returns 502. Re-deploys do NOT deactivate it. Use `zerops_discover` to check current status and get the URL (`subdomainEnabled` + `subdomainUrl` fields).
+- **Activate routing:** `zerops_deploy` **auto-enables** the subdomain on the first deploy for eligible service modes (dev/stage/simple/standard/local-stage) and waits HTTP-ready — the deploy response carries `subdomainAccessEnabled: true` and the URL. Use `zerops_subdomain enable` only as an explicit recovery/ops command if auto-enable was skipped (a worker / non-HTTP service, or launch-production which deliberately opts out in favor of a custom domain). Import's `enableSubdomainAccess: true` pre-configures intent; deploy activates the L7 balancer. Re-deploys do NOT deactivate it. Use `zerops_discover` to check current status and get the URL (`subdomainEnabled` + `subdomainUrl` fields).
- **Port-specific subdomains**: If HTTP ports are defined in zerops.yml, each port gets its own subdomain: `{hostname}-{subdomainHost_prefix}-{port}.{subdomainHost_rest}`. Example: hostname `appdev`, subdomainHost `1df2.prg1.zerops.app`, port 3000 → actual URL `https://appdev-1df2-3000.prg1.zerops.app`. Port 80 omits the port suffix: `https://appdev-1df2.prg1.zerops.app`
- **Internal network fallback**: Every service is accessible internally via `http://{hostname}:{port}` (e.g., `http://appdev:3000`). Use this to verify the app is running when subdomain access is uncertain — `curl http://appdev:3000/health` from the ZCP container or any other service in the project
- Works for: nodejs, static, nginx, go, python, php, java, rust, dotnet, and all other runtime types
@@ -17227,7 +17185,7 @@ Fully managed S3 compatible storage running on a separate infrastructure and per
- [zCLI](/references/cli)
- [zerops.yaml](/zerops-yaml/specification)
-- [Import file](/references/import)
+- [Import YAML](/references/import)
## Feature highlights
@@ -26341,6 +26299,10 @@ Direct IP Access uses [pgBouncer](https://www.pgbouncer.org/) for connection poo
Internally, port `5432` is available without SSL (and port `5433` for reads in HA mode). Externally, connections are secured with TLS through pgBouncer (port `6432`) before being routed to your PostgreSQL service. The read replica port is not available for external connections.
+:::tip Trusting the TLS certificate
+The TLS certificate served on port `6432` is signed by the Zerops Certificate Authority. To verify it from outside Zerops, download and trust the [Zerops CA](/references/networking/zerops-ca) — e.g. `psql "... sslmode=verify-full sslrootcert=./zerops-ca.pem"`.
+:::
+
#### Enable external access
1. Navigate to your PostgreSQL service in the Zerops GUI and choose the **Public Access through IP Addresses** section
@@ -28550,6 +28512,498 @@ For advanced configurations or custom requirements:
- Join our [Discord community](https://discord.gg/zeropsio)
- Contact support via [email](mailto:support@zerops.io)
+----------------------------------------
+
+# Quickstart
+
+
+With this guide, we'll go from zero to a live app with a managed database, a public URL, and auto-deploy on every git push. Takes about 5 minutes.
+
+Here's what we're building together: a page with a button that says **"I followed the Zerops quickstart"**. Every developer who finishes this guide and clicks it gets counted. It's a real app: Express backend, PostgreSQL database, static frontend, all running on **Zerops**.
+
+**See it live before you build it:** [app-25be-3000.prg1.zerops.app](https://app-25be-3000.prg1.zerops.app/)
+[Video: /vids/quickstart-app.webm](/vids/quickstart-app.webm)
+
+:::info Two ways to use this guide
+**Just want to see how Zerops works?** Follow along as-is. The feedback app covers everything: frontend, backend, managed database, private networking, auto-deploy.
+
+**Already have an app?** Pick a recipe matching your stack in Step 1 instead of Node.js. The steps are identical. Then in Step 5, replace the feedback app code with your own. The `zerops.yml` structure stays the same.
+:::
+
+:::tip Before we start
+Sign up at [app.zerops.io](https://app.zerops.io). You get $15 in promo credits on signup, no credit card needed. Verify your account with a $10 payment and get an additional $50, bringing your total to $65 in credits. A simple app with a database costs roughly $3-5/month, so credits go a long way.
+:::
+
+---
+
+## 1. Deploy the recipe
+
+Go to [app.zerops.io/recipes](https://app.zerops.io/recipes). No account needed, the recipes page works even when you're not logged in.
+
+For this guide, find and click **Node.js**. You'll see **Node.js Hello World**, a Node.js app with Express connected to a PostgreSQL database.
+
+Hit **Deploy nodejs-hello-world-small-prod**. If you're not signed in yet, Zerops creates your account and kicks off the deploy in the same step.
+
+:::info What's a recipe?
+A recipe is a working app with infrastructure already configured: managed database, environment variables, `zerops.yaml`, everything connected. It's a correct starting point, not a finished product. We'll swap the code out in Step 5.
+:::
+
+:::note Want a different stack?
+Everything in this guide works the same way for Next.js, Python, Go, Laravel, and more. Just pick the recipe that matches your stack instead. The steps are identical.
+:::
+
+---
+
+## 2. Watch it build
+
+After hitting Deploy, you'll land on the dashboard. On the right side you'll see a pipeline already running.
+
+It goes through these steps in real time:
+
+1. Initializing build container
+2. Running build commands from `zerops.yaml`
+3. Creating app version and upgrading service
+4. Done
+
+:::tip Good to know
+The build container is **temporary and free**. Zerops spins it up, runs your build, saves the output, and deletes it. You're only billed for the running app.
+:::
+
+Once the pipeline finishes, your app is live.
+
+---
+
+## 3. See what got created
+
+Click into your new project. You'll see:
+
+- **app**: your Node.js service, already running
+- **db**: a managed PostgreSQL database, already running
+- **Project core**: load balancer, firewall, logger, all managed by Zerops
+
+All of these are already talking to each other on a private network. Nothing to configure.
+
+:::tip Coming from Vercel and Supabase?
+You're probably used to copying a long database URL and pasting it as an environment variable. On Zerops, services talk to each other by hostname. `DB_HOST` is just `db`, not a URL. You still set credentials in `zerops.yaml`, Zerops fills in the values. No connection strings to manage.
+:::
+
+---
+
+## 4. Open your live app
+
+The Zerops subdomain is already enabled when you deploy from a recipe. Click into your **app** service and open the URL. It looks something like `app-2437-3000.prg1.zerops.app`.
+
+The default recipe app will be there. Next step, we replace it with the feedback app.
+
+When you're ready for production, point a custom domain at your app. Zerops handles the SSL certificate automatically.
+
+---
+
+## 5. Swap in the feedback app
+
+Clone the recipe repo and open it in your editor:
+
+```bash
+git clone https://github.com/zeropsio/recipe-nodejs
+cd recipe-nodejs
+npm install
+```
+
+The repo uses TypeScript. You only need to touch two files: `src/app.ts` and `src/db.ts`. Leave `src/index.ts` and `src/config.ts` exactly as they are.
+
+**Replace `src/db.ts`** with this:
+
+```ts
+
+export const connectDB = async () => {
+ const client = new Client({
+ host: config.db.host,
+ port: config.db.port,
+ user: config.db.username,
+ password: config.db.password,
+ database: config.db.database,
+ });
+
+ await client.connect();
+
+ await client.query(`
+ CREATE TABLE IF NOT EXISTS clicks (
+ id SERIAL PRIMARY KEY,
+ clicked_at TIMESTAMPTZ DEFAULT NOW()
+ )
+ `);
+
+ return client;
+};
+```
+
+**Replace `src/app.ts`** with this:
+
+```ts
+
+const app = express();
+
+app.use(express.static(path.join(__dirname, '../public')));
+
+app.get('/count', async (_, res) => {
+ const client = await connectDB();
+ const result = await client.query('SELECT COUNT(*) FROM clicks');
+ await client.end();
+ res.json({ count: parseInt(result.rows[0].count) });
+});
+
+app.post('/click', async (_, res) => {
+ const client = await connectDB();
+ await client.query('INSERT INTO clicks DEFAULT VALUES');
+ const result = await client.query('SELECT COUNT(*) FROM clicks');
+ await client.end();
+ res.json({ count: parseInt(result.rows[0].count) });
+});
+
+app.get('/status', (_, res) => {
+ res.status(200).send({ status: 'UP' });
+});
+
+export default app;
+```
+
+**Create a `public/` folder** at the repo root and add `public/index.html`:
+
+```html
+
+
+
+
+
+ Zerops Quickstart
+
+
+
+
+
+ zerops
+
+
You made it. 🎉
+
+ You just deployed a real app: managed database, private network,
+ auto-deploy. Let us know you made it through.
+
+
+
+ ...
+
+
+
+
+
+ Node.js 20
+ PostgreSQL 16
+ Zerops
+
+
+
+
+
+```
+
+The `zerops.yml` already exists in the repo. Update `deployFiles` to include the `public` folder:
+
+```yaml
+zerops:
+ - setup: app
+ build:
+ base: nodejs@20
+ prepareCommands:
+ - npm install -g typescript
+ buildCommands:
+ - npm i
+ - npm run build
+ deployFiles:
+ - ./dist
+ - ./node_modules
+ - ./public
+ - ./package.json
+ run:
+ base: nodejs@20
+ ports:
+ - port: 3000
+ httpSupport: true
+ envVariables:
+ NODE_ENV: production
+ DB_NAME: db
+ DB_HOST: db
+ DB_USER: db
+ DB_PASS: ${db_password}
+ start: npm run start:prod
+ healthCheck:
+ httpGet:
+ port: 3000
+ path: /status
+```
+
+Before pushing, point the repo at your own GitHub remote:
+
+```bash
+git remote set-url origin https://github.com/your-username/your-repo.git
+git push -u origin main
+```
+
+Then move on to Step 6 to connect it to Zerops.
+
+:::note Want to build something else instead?
+Skip the feedback app. Clone the repo, keep the `zerops.yml` as-is, and replace `src/app.ts` with your own routes. The DB connection, build pipeline, and env variables all stay the same.
+:::
+
+---
+
+## 6. Connect GitHub and auto-deploy
+
+1. Click into your **app** service
+2. Scroll down to **Pipelines & CI/CD settings**
+3. Click **GitHub** to connect your repo
+4. Select your repo and set **Trigger on** to **Push to Branch**, pick `main`
+5. In the **"Which `setup` from zerops.yml to use"** field, type `app`
+6. Click **Activate pipeline trigger**
+
+That's it. Every push to main now builds and deploys automatically. Zero downtime, Zerops runs the new version alongside the old one, waits for a health check, then switches traffic over.
+
+You can also trigger deploys manually with the Zerops CLI: `zcli push`.
+
+---
+
+## You're live 🎉
+
+Open your app URL. You should see the feedback button app: a big button, a live click count pulled from the database, all running on Zerops.
+
+Here's what's running:
+
+- A real app on production infrastructure
+- A managed PostgreSQL database with no setup, no connection strings, no SDK
+- Auto-deploy on every git push with zero downtime
+- All services on a private network, secure by default
+- Full Linux containers you can SSH into and install anything on
+
+None of the infrastructure needed manual configuration.
+
+---
+
+## If something breaks
+
+Got a 502 or an app crash on startup? Start here.
+
+**Check the runtime logs first.** Dashboard, click your app service, click the three-dot menu, then **Runtime log**. The error will be there, usually in the last few lines.
+
+Two things come up most often on a first deploy:
+
+:::tip Debug locally with VPN
+Install zcli first (see [CLI reference](/references/cli)), then run `zcli vpn up [your-project-id]` and your laptop joins the project's private network. You can connect to `db:5432` directly from your local machine using TablePlus, psql, or any database client. Disable SSL when connecting over VPN, security is handled by the tunnel itself. If `db` doesn't resolve, try `db.zerops` instead.
+:::
+
+---
+
+## What's next
+
+- **[SSH into your container](/references/networking/ssh)**: `zcli service shell [service-name]` for full Linux access
+- **[Custom domain](/references/networking/public-access)**: add your domain, SSL is automatic
+- **[Autoscaling](/features/scaling)**: set min and max CPU and RAM, Zerops scales within that range automatically
+- **[Add more services](/features/infrastructure)**: queues, search engines, object storage, just add them to your project
+- **[Try ZCP](/zcp/quickstart)**: Zerops' AI agent that can deploy, debug, and operate your project
+
+:::note Stuck?
+Jump into the [Zerops Discord](https://docs.zerops.io/discord). The community is active and the team is there.
+:::
+
+
----------------------------------------
# References > Api
@@ -30731,11 +31185,11 @@ Versions listed on the same line are aliases of the same underlying version.
# References > Import
-The Zerops YAML configuration provides powerful capabilities for both importing and exporting projects and services. This documentation covers how to define your infrastructure as code and move configurations between environments.
+The Import YAML configuration provides powerful capabilities for both importing and exporting projects and services. This documentation covers how to define your infrastructure as code and move configurations between environments.
## YAML Configuration Basics
-The Zerops YAML configuration can be used to create or replicate services in Zerops. You can import configurations in two ways:
+The Import YAML configuration can be used to create or replicate services in Zerops. You can import configurations in two ways:
- **Using the GUI**:
- **For projects**: In the Zerops dashboard, click on **Import a project** in the Projects section
@@ -31540,6 +31994,47 @@ The exported YAML files are compatible with:
This allows you to easily move configurations between environments or create new instances of your infrastructure.
+## Editor support (JSON Schema)
+
+Zerops publishes an official [JSON Schema ↗](https://json-schema.org/) for the Import YAML:
+
+```
+https://api.app-prg1.zerops.io/api/rest/public/settings/import-project-yml-json-schema.json
+```
+
+With the schema attached, your editor gives you:
+
+- **Autocomplete** for every key and nested field (project, services, autoscaling, nginx, embedded `zeropsYaml`, …)
+- **Inline documentation** on hover
+- **Validation** — typos, wrong types, and missing required fields are flagged as you type
+- **Enum suggestions** for fields like `corePackage`, `mode`, `cpuMode`, service `type`, and more
+
+### Auto-detection via SchemaStore
+
+The schema is registered with [SchemaStore ↗](https://www.schemastore.org/), so most YAML-aware editors apply it automatically — no setup required — when the file matches:
+
+- `zerops-import.yml`, `zerops-import.yaml`
+- `zerops-*-import.yml`, `zerops-*-import.yaml` (e.g., `zerops-project-import.yaml`, `zerops-service-import.yaml`)
+
+This covers VS Code (with the [YAML extension by Red Hat ↗](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml)), all JetBrains IDEs, and any editor backed by [`yaml-language-server` ↗](https://github.com/redhat-developer/yaml-language-server) (Neovim, Helix, Sublime LSP, …).
+
+### Manual attachment
+
+If your file is named differently, add a modeline at the top:
+
+```yaml
+# yaml-language-server: $schema=https://api.app-prg1.zerops.io/api/rest/public/settings/import-project-yml-json-schema.json
+project:
+ name: project0
+services:
+ - hostname: app
+ type: nodejs@22
+ # ...
+```
+
+The same URL works in any editor that lets you map a schema to a file pattern manually (e.g., `yaml.schemas` in VS Code `settings.json`, or JetBrains' **JSON Schema Mappings** panel).
+
+
----------------------------------------
# References > Log Forwarding
@@ -33645,6 +34140,119 @@ The system creates encrypted tunnels using **UDP** for traffic transmission and
Each Zerops project runs a **WireGuard server**, while the **zCLI** (Zerops Command Line Interface) functions as a **WireGuard client**. This architecture enables authorized users to securely interact with their Zerops projects through the command line interface.
+----------------------------------------
+
+# References > Networking > Zerops Ca
+
+
+Zerops issues TLS certificates for its managed services (for example PostgreSQL via pgBouncer, or Valkey TLS ports) from its own internal Certificate Authority. When you connect to one of these endpoints over TLS from outside Zerops — your laptop, CI runner, or another piece of infrastructure — the client needs to trust the Zerops CA in order to verify the certificate and complete the handshake.
+
+## Download the CA
+
+The Zerops root CA is published as a single PEM file at:
+
+```
+https://app.zerops.io/ca
+```
+
+Fetch it directly:
+
+```bash
+curl -L -o zerops-ca.pem https://app.zerops.io/ca
+```
+
+The downloaded file is a standard PEM-encoded certificate. You can inspect it with `openssl`:
+
+```bash
+openssl x509 -in zerops-ca.pem -noout -subject -issuer -dates
+```
+
+## Inside Zerops
+
+If your application or client runs **inside** a Zerops container, you do not need to download anything — the CA is already available on the local filesystem at:
+
+```
+/etc/zerops-zembed/ca.crt
+```
+
+Point your TLS client at that path the same way you would point it at a downloaded copy (`sslrootcert=/etc/zerops-zembed/ca.crt`, `--cacert /etc/zerops-zembed/ca.crt`, etc.). It is the same certificate that `https://app.zerops.io/ca` serves.
+
+The Zerops CA is also pre-installed into the system trust store of **every Zerops container**, so most TLS libraries will verify Zerops-signed certificates without any explicit `--cacert` / `sslrootcert` configuration. You can confirm this in your own container with any of the following:
+
+```bash
+# 1) Subject hash → matching symlink in the system trust dir (Debian/Ubuntu)
+ls -l "/etc/ssl/certs/$(openssl x509 -noout -subject_hash -in /etc/zerops-zembed/ca.crt).0"
+# e.g. /etc/ssl/certs/59e8696a.0 -> service-intermediate.pem
+
+# 2) Verify the CA file against the merged system bundle
+openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt /etc/zerops-zembed/ca.crt
+# expected: /etc/zerops-zembed/ca.crt: OK
+
+# 3) End-to-end: handshake against a Zerops-signed endpoint without -CAfile
+openssl s_client -connect :6380 -verify_return_error port=6432 user= dbname=db \
+ sslmode=verify-full sslrootcert=./zerops-ca.pem"
+```
+
+Or as a connection string:
+
+```
+postgresql://:@:6432/db?sslmode=verify-full&sslrootcert=./zerops-ca.pem
+```
+
+### redis-cli (Valkey)
+
+```bash
+redis-cli --tls --cacert ./zerops-ca.pem \
+ -h -p 6380 -a
+```
+
+### openssl s_client (debugging)
+
+To confirm the TLS handshake and inspect the served certificate chain:
+
+```bash
+openssl s_client -connect :6432 \
+ -CAfile ./zerops-ca.pem -servername
+```
+
+### System-wide trust
+
+To trust the Zerops CA system-wide (so clients pick it up automatically without an explicit flag):
+
+- **Debian/Ubuntu:** copy to `/usr/local/share/ca-certificates/zerops-ca.crt` and run `sudo update-ca-certificates`
+- **macOS:** `sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain zerops-ca.pem`
+- **Alpine:** copy to `/usr/local/share/ca-certificates/zerops-ca.crt` and run `update-ca-certificates`
+
+:::tip
+For application code, most TLS libraries accept a custom CA bundle without modifying system trust — for example `PGSSLROOTCERT` for libpq, `tls.RootCAs` in Go, or the `ca` option in Node's `tls` module.
+:::
+
+
----------------------------------------
# References > Smtp
@@ -34006,7 +34614,7 @@ zcli project list
### project project-import
-Creates a new project with one or more services from a YAML definition.
+Creates a new project with one or more services from an [Import YAML](/references/import) definition.
```sh
zcli project project-import [flags]
@@ -34018,7 +34626,7 @@ zcli project project-import [flags]
### project service-import
-Creates one or more services in an existing project from a YAML definition.
+Creates one or more services in an existing project from an [Import YAML](/references/import) definition.
```sh
zcli project service-import [flags]
@@ -34179,6 +34787,65 @@ Shows the current zCLI version.
zcli version
```
+### upgrade
+
+Replaces the running zCLI binary in place with a newer release. Downloads the matching asset from GitHub Releases, verifies it against the release's `checksums.txt`, then atomically swaps the binary.
+
+:::note Availability
+The `upgrade` command is available in zCLI `v1.1.0` and later. On earlier versions, install the newer release via [install.sh](#downgrading-below-v110) (or your package manager) first.
+:::
+
+```sh
+zcli upgrade [flags]
+```
+
+**Flags:**
+- `--check` - Print the current and latest version, then exit without installing. Intended for scripts and package managers.
+- `--yes` - Skip the confirmation prompt.
+- `--version string` - Install a specific release tag (e.g. `v1.1.0`) instead of the latest. Allows downgrades.
+- `--pick-version` - Open an interactive picker listing every release. Mutually exclusive with `--version`.
+- `--include-pre-release` - Include pre-release and `-rc` tags in the `--pick-version` picker. Stable releases only by default.
+- `--no-cache` - Bypass the on-disk version cache and resolve `latest` directly from the release API. Useful right after a release goes out, before the local cache refreshes.
+- `--download-timeout string` - Overall timeout for the binary download as a Go duration (e.g. `5m`, `90s`). `0` disables the timeout. Default `2m`.
+
+**Examples:**
+```sh
+# Interactive upgrade to the latest release
+zcli upgrade
+
+# Unattended upgrade, suitable for scripts
+zcli upgrade --yes
+
+# Install a specific tag (and accept downgrade)
+zcli upgrade --version v1.1.0 --yes
+
+# Pick from a table of every release
+zcli upgrade --pick-version
+```
+
+#### Exit codes for `--check`
+
+`zcli upgrade --check` is designed for scripting. It prints `Current:`, `Latest:` (and `Target:` when `--version` is set) on stdout and exits with:
+
+- `0` - up to date.
+- `1` - a newer release is available.
+- `2` - lookup failed (network, invalid `--version` tag, etc.); the error is on stderr.
+- `3` - the resolved target predates `v1.1.0` (the first release that ships `checksums.txt`) and cannot be installed by `zcli upgrade`. Use the install script instead - see below.
+
+#### Package-manager installs
+
+When zCLI is installed through a package manager (`npm`, Homebrew, `nix`, `.deb`), `zcli upgrade` refuses to swap the binary and prints the channel-appropriate command instead - for example `npm install -g @zerops/zcli` or `brew upgrade zcli`. `--check` still works against any install.
+
+#### Downgrading below v1.1.0
+
+Releases before `v1.1.0` don't ship the `checksums.txt` asset that `zcli upgrade` verifies against, so they can only be installed via the install script:
+
+```sh
+curl -fsSL https://raw.githubusercontent.com/zeropsio/zcli/main/install.sh | sh -s -- v1.0.67
+```
+
+`zcli upgrade --version ` and `--pick-version` will print this hint when the chosen target requires the install script.
+
### show-debug-logs
Displays debug logs for troubleshooting.
@@ -38833,6 +39500,10 @@ Our HA implementation uses a unique approach to ensure high availability while m
Be aware that replica data may lag slightly behind the master due to asynchronous replication.
:::
+:::tip Trusting the TLS certificate
+The certificates served on the TLS ports (`6380` and `7001`) are signed by the Zerops Certificate Authority. To verify them from outside Zerops, download and trust the [Zerops CA](/references/networking/zerops-ca) — e.g. `redis-cli --tls --cacert ./zerops-ca.pem -h -p 6380`.
+:::
+
## Learn More
- [Official Valkey Documentation](https://valkey.io/docs) - Comprehensive guide to Valkey features
@@ -39072,7 +39743,7 @@ Use these definitions when a page, workflow status, agent handoff, or policy nee
**Remote setup** - the `zcp` binary running inside a Zerops `zcp@1` service.
-**Include Coding Agent** - remote setup option that adds the bundled agent CLI, currently Claude Code, and preconfigures it to use ZCP MCP tools.
+**Include Coding Agent** - remote setup option that adds a bundled agent CLI (Claude Code, Codex, Antigravity, or Grok Build) and preconfigures it to use ZCP MCP tools.
**Cloud IDE** - browser-based VS Code served by remote setup.
@@ -39184,16 +39855,51 @@ Use these definitions when a page, workflow status, agent handoff, or policy nee
# Zcp > Overview
-:::info Public preview
-ZCP MCP is a public preview and is under active development. If you hit a bug, confusing behavior, or a missing workflow, please report it on [Discord](/discord); feedback from real projects is especially useful.
-:::
-
This section covers, in order:
-- **How a run unfolds.** [Quickstart](/zcp/quickstart) for hands-on; [How it works](/zcp/concept/how-it-works) for the work loop.
-- **Where the agent runs.** [Remote or local setup](/zcp/setup/choose-workspace), [Trust model](/zcp/security/trust-model), and [Production boundary](/zcp/security/production-policy).
-- **What you decide while working.** [Build and ship](/zcp/workflows/build-with-zcp), [Package a running service](/zcp/workflows/package-running-service), [Promote to production](/zcp/workflows/promote-to-production).
-- **Exact labels when they matter.** [Workflows in depth](/zcp/reference/agent-workflow), [ZCP MCP tools](/zcp/reference/mcp-operations), [Troubleshooting](/zcp/reference/troubleshooting), [Glossary](/zcp/glossary).
+
+
+
+
+GET STARTED
+
+
Quickstart and concept
+
+[Quickstart](/zcp/quickstart) for hands-on; [How it works](/zcp/concept/how-it-works) for the work loop.
+
+
+
+
+
+SETUP
+
+
Remote or local workspace
+
+[Remote or local setup](/zcp/setup/choose-workspace), [Trust model](/zcp/security/trust-model), and [Production boundary](/zcp/security/production-policy).
+
+
+
+
+
+WORKFLOWS
+
+
Build, package, promote
+
+[Build and ship](/zcp/workflows/build-with-zcp), [Package a running service](/zcp/workflows/package-running-service), [Promote to production](/zcp/workflows/promote-to-production).
+
+
For the broader feature concept — why coding agents need real project infrastructure rather than a sandbox or generated artifact — start with [Infrastructure for Coding Agents](/features/coding-agents).
@@ -39203,13 +39909,49 @@ Your prompt can stay about the product. Name the stack, runtime layout, acceptan
## What the agent gets
-**Current state.** Services, runtime layout, managed dependencies, env-var keys and references, logs, events, deploy history, verification state, and saved work state.
+
+
+
+
+STATE
+
+### Current state
+
+Services, runtime layout, managed dependencies, env-var keys and references, logs, events, deploy history, verification state, and saved work state.
+
+
+
+
+
+CONTROLS
+
+### Zerops operations
+
+Project-scoped tools for discovering services, changing env vars, managing runtimes, deploying, verifying, scaling, public access, and delivery setup.
+
+
+
+
+
+INSTRUCTIONS
+
+### Workflow
+
+The generated instructions combine service setup and app development: inspect state, choose the runtime target, use or create services, wire code and `zerops.yaml`, deploy, verify, and choose delivery. The Zerops work stays behind the product task instead of becoming another checklist.
+
+
+
+
+
+EVIDENCE
+
+### Evidence-based completion
-**Zerops operations.** Project-scoped tools for discovering services, changing env vars, managing runtimes, deploying, verifying, scaling, public access, and delivery setup.
+A build or deploy is not the finish line. A completed app task should end with a working URL, endpoint result, UI proof, or a blocker backed by logs, events, and verification evidence.
-**Workflow.** The generated instructions combine service setup and app development: inspect state, choose the runtime target, use or create services, wire code and `zerops.yaml`, deploy, verify, and choose delivery. The Zerops work stays behind the product task instead of becoming another checklist.
+
-**Evidence-based completion.** A build or deploy is not the finish line. A completed app task should end with a working URL, endpoint result, UI proof, or a blocker backed by logs, events, and verification evidence.
+
## What you no longer have to script
@@ -39231,7 +39973,7 @@ To start, add remote setup in Zerops or initialize local setup beside your edito
## Your agent, credentials, and workspace
-**Agent account.** Remote setup can include a bundled agent CLI, currently Claude Code, already configured for MCP. Zerops wires the agent to the tools; you still authenticate with your own subscription login or API credentials.
+**Agent account.** ZCP supports multiple coding agents including Claude Code (Anthropic), Codex (OpenAI), Antigravity, and Grok Build. Remote setup can bundle one of these, already configured for MCP. Zerops wires the agent to the tools; you still authenticate with your own subscription login or API credentials.
**Zerops token.** The MCP server connects through `ZCP_API_KEY`, a Zerops token limited to one project. Remote setup gets it from the platform; local setup reads it from `.mcp.json`. Token details live in [Tokens and credentials](/zcp/security/tokens-and-project-access).
@@ -39251,7 +39993,9 @@ This section is not a replacement for Zerops platform references. The Zerops [bu
# Zcp > Quickstart
-Use this when you want the fastest hands-on ZCP loop: deploy an **AI Agent** recipe, authorize Claude Code, open Browser VS Code, and ask for one product change.
+Use this when you want the fastest hands-on ZCP loop: deploy an **AI Agent** recipe, authorize your coding agent, open Browser VS Code, and ask for one product change.
+
+ZCP supports multiple coding agents including Claude Code (Anthropic), Codex (OpenAI), Antigravity, and Grok Build. The screenshots below use Claude Code as the walkthrough example.
Some [Zerops recipes](https://app.zerops.io/recipes) include an **AI Agent** environment. That preset creates app services, managed services, the `zcp@1` workspace, Browser VS Code, and bundled agent wiring in one deploy.
@@ -39260,7 +40004,7 @@ This quickstart uses [Laravel showcase](https://app.zerops.io/recipes/laravel-sh
## Prerequisites
- A Zerops account with permission to create a project.
-- A Claude Code subscription login or API authentication. Zerops wires Claude Code to ZCP, but your agent subscription or model credentials stay yours.
+- A subscription login or API credentials for your chosen coding agent (Claude Code, Codex, Antigravity, or Grok Build). Zerops wires the agent to ZCP, but your agent subscription or model credentials stay yours.
## 1. Choose the AI Agent recipe
@@ -39272,23 +40016,23 @@ This quickstart uses [Laravel showcase](https://app.zerops.io/recipes/laravel-sh
The deploy creates app runtimes, managed dependencies, and a `zcp@1` workspace. In this recipe it appears as the `zcp` service. The agent, terminal, and browser IDE run there. App code still deploys to the app runtimes, not to `zcp`.
-## 2. Authorize Claude Code
+## 2. Authorize your coding agent
-When provisioning finishes, the dashboard opens the Claude Code authentication flow. Use your own Claude Code subscription login or API credentials.
+When provisioning finishes, the dashboard opens the authentication flow for your bundled agent. If you are using Claude Code (as in the screenshots below), use your own Claude Code subscription login or API credentials.
-This is separate from `ZCP_API_KEY`, the Zerops token used by ZCP. Your Claude login or API key is used only by the bundled agent.
+This is separate from `ZCP_API_KEY`, the Zerops token used by ZCP. Your agent login or API key is used only by the bundled agent.
If you close the prompt, open the `zcp` service in the dashboard. Its panel shows the browser workspace, web terminal, SSH access, desktop editor access, and agent authorization state.
## 3. Open the workspace
-After authentication, continue into **Browser VS Code**. The workspace opens with files, ZCP configuration, terminal access, and the Claude Code panel.
+After authentication, continue into **Browser VS Code**. The workspace opens with files, ZCP configuration, terminal access, and your coding agent panel (the Claude Code panel in the screenshots below).
You are now inside the remote workspace. The agent can read live state, use the MCP tools, reach private services, and deploy app changes to the runtimes created by the recipe.
## 4. Ask for a product outcome
-In Claude Code, ask for the app behavior in natural language. A good first prompt is intentionally short:
+In your coding agent, ask for the app behavior in natural language. A good first prompt is intentionally short:
```text
Build a task board for my team.
@@ -40236,7 +40980,7 @@ A remote workspace puts the agent, terminal, and optional browser IDE inside Zer
The `zcp@1` service runs the same `zcp` binary used by local setup, but broad shell permissions and private service access stay in a clean Zerops service instead of on your laptop.
-Use remote setup when you want the default workspace, a safer boundary for broad agent permissions, or a preconfigured environment with Claude Code and Browser VS Code.
+Use remote setup when you want the default workspace, a safer boundary for broad agent permissions, or a preconfigured environment with a bundled coding agent and Browser VS Code.
App code still deploys to your app runtime services. The `zcp` service is the workspace and control surface; it is not the application runtime.
@@ -40246,7 +40990,7 @@ Taking over is straightforward in this setup. You open the same workspace, termi
- **`zcp@1` workspace service.** Runs ZCP inside Zerops and gives the agent project-scoped operations.
- **Platform-injected `ZCP_API_KEY`.** Zerops injects the token into the workspace; you normally do not set it by hand.
-- **Bundled Claude Code when enabled.** The **Include Coding Agent** option installs and preconfigures Claude Code. You authenticate with your own Claude subscription login or API key.
+- **Bundled coding agent when enabled.** The **Include Coding Agent** option installs and preconfigures one of the supported agents: Claude Code (Anthropic), Codex (OpenAI), Antigravity, or Grok Build. You authenticate with your own subscription login or API credentials.
- **Browser VS Code when enabled.** The **Cloud IDE** option gives you a browser editor, terminal, and a place to supervise or take over the agent session.
- **Private networking.** The workspace can reach managed services by hostname without laptop VPN.
- **Open workspace model.** You can add other agent CLIs, private MCP servers, helper processes, dotfiles, package installs, or a derived team image.
@@ -40257,7 +41001,7 @@ For the local alternative, see [Run locally](/zcp/setup/local-agent-bridge). For
### First-time trial
-Use the [Quickstart](/zcp/quickstart) when you want the guided recipe route. It covers the recipe catalog, **AI Agent** environment, Claude Code authentication, Browser VS Code, first product prompt, and proof.
+Use the [Quickstart](/zcp/quickstart) when you want the guided recipe route. It covers the recipe catalog, **AI Agent** environment, coding agent authentication, Browser VS Code, first product prompt, and proof.
After provisioning, continue with a product prompt in [Build and ship](/zcp/workflows/build-with-zcp).
@@ -40265,7 +41009,7 @@ After provisioning, continue with a product prompt in [Build and ship](/zcp/work
Use this when you want a guided stack baseline for development or staging. A recipe with an **AI Agent** environment creates app services, managed services, and the `zcp@1` workspace together.
-Keep **Coding Agent** enabled when you want bundled Claude Code. Keep **Cloud IDE** enabled when you want Browser VS Code.
+Keep **Coding Agent** enabled when you want a bundled coding agent. Keep **Cloud IDE** enabled when you want Browser VS Code.
### New Zerops setup with remote setup enabled
@@ -40274,7 +41018,7 @@ Use this when you want blank services or a custom stack.
1. Open [Add new project](https://app.zerops.io/dashboard/project-add).
2. Enter the project name, region, and tags.
3. Enable the `zcp@1` remote setup service.
-4. Keep **Include Coding Agent** enabled if you want bundled Claude Code.
+4. Keep **Include Coding Agent** enabled if you want a bundled coding agent.
5. Keep **Cloud IDE** enabled if you want browser VS Code.
6. Create the project.
@@ -40295,9 +41039,9 @@ For a returning remote workspace, open the existing `zcp` service:
1. Open the project in the [Zerops dashboard](https://app.zerops.io/).
2. Open the `zcp` service.
3. Use **Browser VS Code** when **Cloud IDE** is enabled.
-4. Complete the Claude Code login or API-token flow if prompted.
+4. Complete your coding agent login or API-token flow if prompted (Claude Code, Codex, Antigravity, or Grok Build).
-After authentication, Claude Code is connected to ZCP and ready to work from the Browser VS Code terminal. If the workspace was already authorized, use the same route to resume, supervise, or take over work.
+After authentication, your coding agent is connected to ZCP and ready to work from the Browser VS Code terminal. If the workspace was already authorized, use the same route to resume, supervise, or take over work.
First load can take a minute while the image, Cloud IDE, and bundled agent finish starting. If the page opens before the service is ready, wait until the service is running and reload.
@@ -40309,7 +41053,7 @@ Editors that support remote development can connect to the workspace or runtime
This keeps the agent and private network inside Zerops while letting you use a desktop editor UI. Broader editor patterns live in [Local & Remote Development](/features/local-remote-development#native-ide-over-ssh).
-You can also install another agent CLI or additional MCP servers inside the `zcp` service. The bundled Claude Code flow is a convenience, not a closed product boundary.
+You can also install another agent CLI or additional MCP servers inside the `zcp` service. The bundled agent flow is a convenience, not a closed product boundary.
## Advanced customization guardrails
@@ -40322,7 +41066,7 @@ Tools installed inside the `zcp` service may see workspace environment variables
| Agent workspace | The `zcp@1` service: agent CLI, browser VS Code, shell tools, MCP servers, helper processes, dotfiles. |
| App code deploys | Your app runtime services; not the `zcp` workspace service. |
| `ZCP_API_KEY` | Injected by Zerops into the `zcp` workspace. |
-| Agent account | Your Claude subscription login or model API credential. Zerops wires the agent to ZCP, but the agent account remains yours. |
+| Agent account | Your agent subscription login or model API credential. Zerops wires the agent to ZCP, but the agent account remains yours. |
| Git credentials | Configured inside the workspace when the agent should commit or push from remote setup. |
| Production release | A separate production project and release process. |
| Production release | A separate production project and release process. |
@@ -40362,7 +41106,7 @@ Use it when the agent should work next to local files, local data, your desktop
[Remote setup](/zcp/setup/hosted-workspace) is the safer default when the agent does not need local files or tools. Use local setup when local control is the point.
-:::warning Public preview
+:::warning Local setup maturity
Local setup has more moving parts than remote setup and may change faster. The binary install path, `.mcp.json` shape, and files written by `zcp init` are still settling between releases.
:::
@@ -41858,5 +42602,43 @@ For more detailed information on specific configurations, refer to the runtime-s
*Need help? Join our [Discord community](https://discord.gg/zeropsio).*
+## Editor support (JSON Schema)
+
+Zerops publishes an official [JSON Schema ↗](https://json-schema.org/) for `zerops.yaml`:
+
+```
+https://api.app-prg1.zerops.io/api/rest/public/settings/zerops-yml-json-schema.json
+```
+
+With the schema attached, your editor gives you:
+
+- **Autocomplete** for every key and nested field
+- **Inline documentation** on hover
+- **Validation** — typos, wrong types, and missing required fields are flagged as you type
+- **Enum suggestions** for fields like `base` or `cache`
+
+### Auto-detection via SchemaStore
+
+The schema is registered with [SchemaStore ↗](https://www.schemastore.org/), so most YAML-aware editors apply it automatically — no setup required — when the file is named:
+
+- `zerops.yml`
+- `zerops.yaml`
+
+This covers VS Code (with the [YAML extension by Red Hat ↗](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml)), all JetBrains IDEs, and any editor backed by [`yaml-language-server` ↗](https://github.com/redhat-developer/yaml-language-server) (Neovim, Helix, Sublime LSP, …).
+
+### Manual attachment
+
+If your file is named differently, add a modeline at the top:
+
+```yaml
+# yaml-language-server: $schema=https://api.app-prg1.zerops.io/api/rest/public/settings/zerops-yml-json-schema.json
+zerops:
+ - setup: app
+ # ...
+```
+
+The same URL works in any editor that lets you map a schema to a file pattern manually (e.g., `yaml.schemas` in VS Code `settings.json`, or JetBrains' **JSON Schema Mappings** panel).
+
+
----------------------------------------
diff --git a/apps/docs/static/llms-small.txt b/apps/docs/static/llms-small.txt
index 814c469a2..ad3a3c6a3 100644
--- a/apps/docs/static/llms-small.txt
+++ b/apps/docs/static/llms-small.txt
@@ -9079,7 +9079,7 @@ Most coding-agent platforms went agent-first, then bolted on infrastructure —
### Your agent, your subscription
-Bring whichever agent you already use. Claude Code today; Codex, Gemini CLI, opencode, and any MCP-capable client next. The container is a regular Ubuntu — install your own CLI tools, drop in your `.claude` / `.cursor` configs, attach your IDE over SSH. **Zerops doesn't resell tokens or proxy your model calls** — sign in with your own Anthropic / OpenAI / Google subscription and the agent talks to its provider directly.
+ZCP supports multiple coding agents including Claude Code (Anthropic), Codex (OpenAI), Antigravity, and Grok Build. The container is a regular Ubuntu — install your own CLI tools, drop in your `.claude` / `.cursor` configs, attach your IDE over SSH. **Zerops doesn't resell tokens or proxy your model calls** — sign in with your own Anthropic / OpenAI / Google subscription and the agent talks to its provider directly.
### An ordinary Zerops project underneath
@@ -9097,7 +9097,7 @@ Runtimes for Bun, Deno, Node.js, Go, Python, Rust, Java, .NET, PHP, Elixir, Glea
The agent reaches your project's private network one of two ways:
-- **Remote** — a `zcp` service deployed into the project runs the agent. You attach to it with Claude Code's IDE extension, with any IDE that supports remote development (Cursor, Windsurf, VS Code Remote), or by running [`zcli vpn up`](/references/networking/vpn) and ssh-ing into `zcp` to drive the rest of the project from a shell.
+- **Remote** — a `zcp` service deployed into the project runs the agent. You attach to it with your agent's IDE extension or terminal, with any IDE that supports remote development (Cursor, Windsurf, VS Code Remote), or by running [`zcli vpn up`](/references/networking/vpn) and ssh-ing into `zcp` to drive the rest of the project from a shell.
- **Local** — install the `zcp` MCP on your machine and run `zcli vpn up` to join the network. From there your IDE, agent, and shell can ssh directly into any container.
Either way, the agent reaches [managed services by hostname](/references/networking/internal-access) (`db:5432`, `cache:6379`), deploys through the [Zerops pipeline](/features/pipeline), and reads logs and events the same way you would.
@@ -9235,47 +9235,47 @@ With the model clear, here's where ZCP sits among adjacent tools. People say "ag
_AWS MCP servers · Railway MCP · Fly.io MCP · Render MCP_
-Most major PaaS providers have shipped an MCP — provision services, deploy code, list resources, read operational state. Great for "let my agent ship to my Railway account." These are *deploy and operate* surfaces, driven from outside the platform — and they reflect what's underneath: platforms optimized for day-one deploy that tuck the infrastructure behind a wall. Once an agent needs to actually *develop* against that infrastructure — debug a failed health check, follow real logs, hit Postgres from inside the network, inspect what a build is doing, run the dev loop before it ships anything — the wall stops it. That's by design on those platforms, not a missing feature.
+Most major PaaS providers have shipped an MCP — provision services, deploy code, list resources, read operational state. Great for "let my agent ship to my Railway account." These are *deploy and operate* surfaces, driven from outside the platform — and they reflect what's underneath: platforms optimized for day-one deploy that tuck the infrastructure behind a wall. Log and metric read tools landed across the category in 2025 (and AWS only just hit GA), but the **in-network, in-container** surface an agent needs to actually *develop* — hit Postgres from inside the network, follow a build live, drive the dev loop before it ships anything — is still on the other side of the wall.
#### Cloud VPS MCPs
_Hetzner Cloud MCP · DigitalOcean MCP · Linode MCP · raw SSH/server MCPs_
-"Let your agent manage your Hetzner VPS." An MCP gives the agent access to a Linux box — provision it, SSH in, install Docker and Postgres and nginx, set up systemd units, point a domain at it. Maximum control, lowest cost, full Linux to play with. The same reason senior developers reach for managed platforms applies here: even if you *can* harden SSH, write nginx configs, tune `pg_hba.conf`, rotate TLS, set firewall rules, run fail2ban, and stay on top of CVEs across kernel, OpenSSL, Docker, Postgres, and nginx — you usually don't want to. Each layer is its own domain with its own gotchas, each is a security surface that drifts the moment you stop tending it, and every project becomes a snowflake. Hand that work to an agent and you also hand it the blast radius: misconfigured firewall, debug endpoint left open, port 5432 exposed to the internet, keys never rotated. ZCP is the inverse trade-off — the **guardrails** of a managed platform. Private networking, TLS, isolated services, safe defaults, managed backups, no exposed ports unless you opt in — all built in. The agent operates through [project-scoped MCP tools](/zcp/reference/mcp-operations) instead of `sudo` on a fresh Ubuntu box, so the mistakes that matter on a VPS aren't reachable from where it sits.
+"Let your agent manage your Hetzner VPS." Two shapes cluster here: vendor-API MCPs (DigitalOcean ships an official one) that provision services from outside the box, and community-built SSH MCPs (Hetzner, Linode, Vultr) that give the agent shell access — provision it, SSH in, install Docker and Postgres and nginx, set up systemd units, point a domain at it. Maximum control, lowest cost, full Linux to play with. The same reason senior developers reach for managed platforms applies here: even if you *can* harden SSH, write nginx configs, tune `pg_hba.conf`, rotate TLS, set firewall rules, run fail2ban, and stay on top of CVEs across kernel, OpenSSL, Docker, Postgres, and nginx — you usually don't want to. Each layer is its own domain with its own gotchas, each is a security surface that drifts the moment you stop tending it, and every project becomes a snowflake. Hand that work to an agent and you also hand it the blast radius: misconfigured firewall, debug endpoint left open, port 5432 exposed to the internet, keys never rotated. ZCP is the inverse trade-off — the **guardrails** of a managed platform. Private networking, TLS, isolated services, safe defaults, managed backups, no exposed ports unless you opt in — all built in. The agent operates through [project-scoped MCP tools](/zcp/reference/mcp-operations) instead of `sudo` on a fresh Ubuntu box, so the mistakes that matter on a VPS aren't reachable from where it sits.
#### Cloud dev environments with AI
-_GitHub Codespaces + Copilot Workspace · Gitpod · Coder_
+_GitHub Codespaces + Copilot Coding Agent · Ona (ex-Gitpod) · Coder_
-A managed Linux container in the cloud with your editor and an AI assistant attached. Solves "where the agent runs" so state survives between sessions and machine setup stops being a question. The `zcp` service is the closest thing in this category — managed Linux container, Cloud IDE, your agent of choice — except it lives *inside* a Zerops project, addressing the project's runtimes, database, and cache by hostname, with deploys and logs as primitives the agent can call.
+A managed Linux container in the cloud with your editor and an AI assistant attached. Solves "where the agent runs" so state survives between sessions and machine setup stops being a question. The category itself is repositioning toward **governed agent runtimes** — Copilot Coding Agent (the productized successor to Workspace), Coder Agents, and Ona (Gitpod's rebrand after it shut down the SaaS in late 2025) all point the same way. The `zcp` service is the closest thing in this category — managed Linux container, Cloud IDE, your agent of choice — except it lives *inside* a Zerops project, addressing the project's runtimes, database, and cache by hostname, with deploys and logs as primitives the agent can call.
#### Bundled agent platforms
-_Replit Agent · Lovable · Bolt.new · v0 · Devin · OpenHands_
+_Replit Agent · Lovable · Bolt.new · v0 · Devin_
-The agent, the workspace, the stack, and (often) the hosting target are fused into one closed product. Fast for prototypes. Decisions are made for you. Switching agents usually means switching platforms, and production-grade primitives — a real dev/stage/prod release flow, private networking, observability — tend to be limited or absent. **ZCP doesn't bundle**: the agent and model stay yours on your own subscription, and the platform underneath is normal Zerops with the full stack of managed services, networking, deploys, and observability.
+The agent, the workspace, the stack, and (often) the hosting target are fused into one closed product. Fast for prototypes. Decisions are made for you. Switching agents usually means switching platforms, and production-grade primitives — a real dev/stage/prod release flow, private networking, observability — are **uneven** across this category: v0, Bolt, and Devin have moved upmarket with deploy/auth/DB primitives, others have not. **ZCP doesn't bundle**: the agent and model stay yours on your own subscription, and the platform underneath is normal Zerops with the full stack of managed services, networking, deploys, and observability.
#### Local coding agents
-_Cursor · Windsurf · Zed · Claude Code · Codex CLI · Aider · Cline_
+_Cursor · Windsurf · Zed · Claude Code · Codex · Antigravity · Grok Build · Aider · Cline_
-The agent runs on your machine, edits your local checkout, runs local commands. Excellent at code changes. Anything beyond your machine — databases, networking, deploy targets, runtime logs — is yours to wire in. Install the ZCP MCP locally and run `zcli vpn up`, and any of these agents can now reach a real Zerops project alongside your local code: services addressed by hostname, deploys, logs, events.
+The agent runs on your machine, edits your local checkout, runs local commands. Excellent at code changes. **MCP** is now native across these tools, so external reach — databases, networking, deploy targets, runtime logs — comes through plugins instead of bare hands. The agent still lives on your laptop, though: anything off-machine has to be reached, not *inhabited*. Install the ZCP MCP locally and run `zcli vpn up`, and any of these agents can now reach a real Zerops project alongside your local code: services addressed by hostname, deploys, logs, events.
#### Code-execution sandboxes
_E2B · Modal · Daytona · CodeSandbox SDK_
-Ephemeral Linux environments that AI *applications* spin up — often per request — to execute generated code safely. The right primitive when you're building a product that needs a model to run untrusted code and hand back the output. They're a building block for AI applications, not somewhere a coding agent settles in to iterate on your project. Different shape from ZCP; they show up here because the names cluster nearby.
+Mostly ephemeral Linux environments that AI *applications* spin up — often per request — to execute generated code safely (E2B, Modal). The right primitive when you're building a product that needs a model to run untrusted code and hand back the output. Some have pivoted toward **stateful, resumable agent workspaces** — Daytona now explicitly markets "every agent a computer," and CodeSandbox SDK's hibernation/resume sits between ephemeral and persistent. Still a different shape from ZCP; they show up here because the names cluster nearby.
#### Agent SDKs and frameworks
-_Cloudflare Agents · Vercel AI SDK · Mastra · Anthropic Agent SDK_
+_Cloudflare Agents · Vercel AI SDK · Mastra · Claude Agent SDK_
Libraries for building and shipping agents to *your* users — tool calling, memory, orchestration, model providers, sometimes hosting. They're how somebody would build a product like ZCP, not where a coding agent runs against a project. Same disambiguation — adjacent on the shelf, different shape.
## Where to start
-- [Quickstart](/zcp/quickstart) — AI Agent recipe, Claude Code, and a real product change in about five minutes.
+- [Quickstart](/zcp/quickstart) — AI Agent recipe, bundled coding agent, and a real product change in about five minutes.
- [ZCP MCP overview](/zcp/overview) — What the `zcp` MCP gives the agent, where it runs, and how a run ends in proof or a blocker.
- [Remote or local setup](/zcp/setup/choose-workspace) — Choose where the `zcp` MCP runs — inside Zerops with bundled tools, or beside your local editor.
- [Build and ship](/zcp/workflows/build-with-zcp) — Runtime layout, development, delivery, packaging, and production release.
@@ -10353,9 +10353,9 @@ In **Pipelines & CI/CD settings** section of your service detail:
- **Re-deploy last pipeline** - With optional secret env variable updates
- **Trigger new pipeline** - From git repo or with custom configuration
-#### Using import YAML
+#### Using Import YAML
-Add `buildFromGit: ` to your service configuration for one-time build during import. See [import documentation](/references/import#service-basic-configuration).
+Add `buildFromGit: ` to your service configuration for one-time build during import. See [Import YAML documentation](/references/import#service-basic-configuration).
## Build phase
@@ -15159,7 +15159,7 @@ When using SSHFS (`zerops_mount`) for dev workflows, deploy replaces the contain
# Guides > Environment Variables
-Zerops manages environment variables at two scopes (project and service) with strict build/runtime isolation. Variables are set via zerops.yml, import.yml, or GUI. **Both project-level vars AND cross-service vars (`${hostname_varname}`) auto-inject as OS env vars into every container in the project** — no declaration required. `run.envVariables` exists only for mode flags and framework-convention renames. Re-declaring an auto-injected var under its own name creates a literal-string self-shadow. Secret vars are write-only after creation. Changes require service restart.
+Zerops manages environment variables at two scopes (project and service) with strict build/runtime isolation. Variables are set via zerops.yml, import.yml, or GUI. **Project vars auto-inherit into every service** — read them directly, no declaration. **Cross-service (sibling) vars do NOT auto-inject under the default `envIsolation=service`** — reference a sibling's value explicitly as `${hostname_varname}` in `run.envVariables` (only legacy `none` mode injects siblings as bare vars). Secret reads are privilege-gated (an admin token returns the value; a read-only token gets `REDACTED`). A running process keeps its boot-time env — restart it (not reload) to pick up a changed value.
---
@@ -15167,21 +15167,21 @@ Zerops manages environment variables at two scopes (project and service) with st
| Scope | Defined In | Visibility | Editable Without Redeploy |
|-------|-----------|------------|--------------------------|
-| **Project** | import.yml `project.envVariables`, GUI | All services (auto-inherited) | Yes (restart required) |
-| **Service secret** | import.yml `envSecrets`, GUI | Single service | Yes (restart required) |
+| **Project** | import.yml `project.envVariables`, GUI | All services (auto-inherited) | Yes (restart to apply) |
+| **Service secret** | import.yml `envSecrets`, GUI | Single service | Yes (restart to apply) |
| **Service basic (build)** | zerops.yml `build.envVariables` | Build container only | No (redeploy required) |
| **Service basic (runtime)** | zerops.yml `run.envVariables` | Runtime container only | No (redeploy required) |
| **Service basic (runtime)** | zerops.yml `run.envVariables` | Runtime container only | No (redeploy required) |
## Variable Precedence
-When the same key exists at multiple levels:
+Total order for the bare key (highest wins): **system/platform > yaml-baked `run.envVariables` > service secret/userData > project**.
-1. **Service basic (build/runtime)** wins over service secret
-2. **Service-level** wins over project-level
-3. Build and runtime are **separate environments** -- same key can have different values in each
+1. **yaml-baked `run.envVariables` owns its key** — a service secret/userData set on the same key is **rejected** (`userDataDuplicateKey`); the two never coexist. To change a yaml-baked value, edit `zerops.yml` and redeploy.
+2. **Service-level** wins over **project-level**.
+3. Build and runtime are **separate environments** -- same key can have different values in each.
-**DO NOT** create a secret and a basic runtime variable with the same key expecting both to persist. The basic runtime variable from zerops.yml silently overrides the secret.
+**DO NOT** set a secret/service var on a key already declared in `run.envVariables` — the platform rejects it. The yaml var owns the key; edit the yaml and redeploy instead.
## Build/Runtime Isolation
@@ -15204,104 +15204,62 @@ zerops:
API_KEY: "12345-abcde"
```
-## Cross-Service References — Auto-Injected Project-Wide
+## Cross-Service References — Explicit `${hostname_varname}` Required
-**Every service's variables are automatically injected as OS environment variables into every other service's containers** — both runtime and build. A worker container sees `db_hostname`, `db_password`, `queue_user`, `storage_apiUrl`, etc. as real OS env vars at container start. Zero declaration in zerops.yml required.
-
-Read them directly in application code:
-
-```javascript
-// Node — lowercase native names match the platform
-const host = process.env.db_hostname;
-const pwd = process.env.db_password;
-const natsUser = process.env.queue_user;
-```
-
-```php
-// PHP
-$host = getenv('db_hostname');
-```
-
-`run.envVariables` and `build.envVariables` have **two legitimate uses only**:
-
-1. **Mode flags** — per-setup values that don't come from another service:
- ```yaml
- run:
- envVariables:
- NODE_ENV: production
- APP_ENV: local
- ```
-
-2. **Framework-convention renames** — forward a platform var under a different name because the framework config expects it. The key on the left MUST DIFFER from the source var name on the right:
- ```yaml
- run:
- envVariables:
- DB_HOST: ${db_hostname} # TypeORM expects uppercase DB_HOST
- DATABASE_URL: ${db_connectionString}
- ```
-
-**Do NOT re-declare auto-injected vars under their own name.** It is always wrong and never useful:
+Under the default `envIsolation=service`, a service does **NOT** automatically see another service's variables — **not even a managed database's connection vars**. To use a sibling's value, reference it explicitly in `run.envVariables`; the left-hand key is the name your app reads, the right-hand `${hostname_varname}` is the source:
```yaml
run:
envVariables:
- db_hostname: ${db_hostname} # SELF-SHADOW — see next section
- db_password: ${db_password} # SELF-SHADOW
- queue_hostname: ${queue_hostname} # SELF-SHADOW
- API_URL: ${API_URL} # SELF-SHADOW (project-level variant)
+ DB_HOST: ${db_hostname}
+ DB_PASS: ${db_password}
+ DATABASE_URL: ${db_connectionString}
+ CACHE_URL: ${cache_connectionString}
```
-The referenced variable does **not** need to exist at definition time — Zerops resolves at container start.
-
-### Self-Shadow Trap
-
-Writing `varname: ${varname}` in `run.envVariables` creates a literal-string self-shadow. The platform's interpolator sees the service-level variable of that name first, can't recurse back to the auto-injected value, and the resolved OS env var becomes the literal string `${varname}`:
-
-```yaml
-run:
- envVariables:
- db_hostname: ${db_hostname} # OS env: db_hostname='${db_hostname}' (literal)
- db_password: ${db_password} # OS env: db_password='${db_password}' (literal)
+```javascript
+// App reads the names you mapped above:
+const host = process.env.DB_HOST;
```
-At runtime, the worker tries to connect to `"${db_hostname}:5432"` and crashes. The fix is to **delete the entire block** — those vars are already in the container's env without any declaration.
-
-This applies identically to project-level vars (`${API_URL}`, `${APP_SECRET}`) and cross-service vars (`${db_hostname}`, `${queue_user}`) — both auto-propagate, both self-shadow under the same rule.
+- The reference **resolves at container start**, independent of isolation mode — the referenced var does not need to exist at definition time.
+- An **unresolved ref stays literal** (`${db_hostname}` reaches the process verbatim) — no error, no blank. A wrong hostname/var on the right-hand side becomes a literal string and the app fails at connect time.
+- **Hostname transformation**: dashes become underscores. Service `my-db` variable `port` is `${my_db_port}`.
-**Hostname transformation**: dashes become underscores. Service `my-db` variable `port` is `${my_db_port}`.
+Only legacy `envIsolation=none` auto-injects every sibling's vars as bare `_KEY` OS env vars without a ref — see Isolation Modes. New projects are `service`; rely on explicit refs.
### Cross-Service References in API vs Runtime
-Cross-service references (`${hostname_varname}`) are **resolved at container start time**, not at definition time. This means:
+Cross-service references (`${hostname_varname}`) are **resolved at container start time**, not at definition time:
-- **`zerops_discover` with `includeEnvs=true`** returns the **literal template** (e.g., `${db_password}`), NOT the resolved value. This is expected — the API stores templates, not resolved values.
+- **`zerops_discover` with `includeEnvs=true`** returns the **literal template** (e.g., `${db_password}`), NOT the resolved value. The service-env API stores templates, not resolved values, and returns only the service's own user-set + intrinsic vars — yaml-baked `run.envVariables` come from the app-version, project vars from the project scope. Assemble across scopes (or read in-container) for the effective env.
- **Inside the running container**, environment variables contain the actual resolved values.
-- **Restarting a service does NOT change** what `zerops_discover` returns — it always shows templates. To verify resolved values, check from inside the container (e.g., via SSH or application endpoint).
+- **Restarting a service does NOT change** what `zerops_discover` returns — it always shows templates. To verify resolved values, check from inside the container.
### Isolation Modes (envIsolation)
-`envIsolation` does NOT control whether cross-service vars auto-inject — they do, in every mode. It controls something narrower: how `${hostname_varname}` templates inside zerops.yml and import.yml *resolve* during platform interpolation.
+`envIsolation` is a project-scope setting that controls whether sibling-service vars are auto-injected.
| Mode | Behavior |
|------|----------|
-| `service` (default) | Service-scoped: `${hostname_varname}` templates inside that service's YAML resolve by following the hostname prefix. The OS env in every container still contains every other service's vars as auto-injected keys. |
-| `none` (legacy) | Cross-service references can be written without the `${hostname_varname}` prefix (e.g. `${password}` resolves to the nearest match). Do not use for new projects — ambiguous, error-prone. |
-| `none` (legacy) | Cross-service references can be written without the `${hostname_varname}` prefix (e.g. `${password}` resolves to the nearest match). Do not use for new projects — ambiguous, error-prone. |
+| `service` (default) | **Siblings are isolated.** A service sees only its own vars + project vars + the explicit `${hostname_varname}` refs it declares in `run.envVariables`. Managed-service connection vars also require an explicit ref. |
+| `none` (legacy) | Every service's vars are auto-injected into every other container as bare `_KEY` OS env vars (source-side, directional). Ambiguous and broad — avoid for new projects. |
+| `none` (legacy) | Every service's vars are auto-injected into every other container as bare `_KEY` OS env vars (source-side, directional). Ambiguous and broad — avoid for new projects. |
Set in import.yml at project or service level:
```yaml
project:
- envIsolation: none # legacy — avoid
+ envIsolation: none # legacy — avoid; default is service
services:
- hostname: db
- envIsolation: none # legacy — avoid
+ envIsolation: none # per-service: expose THIS service's vars to siblings
```
-**Default (`service`) is the right choice.** The auto-inject behavior above applies under the default.
+**Default (`service`) is the right choice.** Wire cross-service explicitly with `${hostname_varname}` — it works in both modes, so code stays correct if isolation ever changes.
## Project Variables -- Auto-Inherited
-Project variables are **automatically available in every service, in both runtime AND build containers**. The platform injects them as OS env vars at container start in every service's runtime container and also in every service's build container during the build phase. From zerops.yaml's point of view they are referenced **directly by name** with `${VAR_NAME}` — **no `RUNTIME_` prefix in either scope**. The `RUNTIME_` prefix is reserved for a different use case: lifting a single service's service-level runtime variable into that same service's build context. Project-scope vars are broader than service-scope and do not need lifting.
+Project variables are **automatically available in every service, in both runtime AND build containers** — injected as OS env vars at container start. From application code, read them directly (`process.env.API_URL`). From zerops.yaml, reference them by name with `${VAR_NAME}` — **no `RUNTIME_` prefix** (that prefix is only for lifting a service's own runtime var into its build context).
**In shell commands** (buildCommands, initCommands, start) project vars are directly readable:
```yaml
@@ -15311,42 +15269,42 @@ build:
- VITE_API_URL=$API_URL npm run build # or pass it forward by shell prefix
```
-**In `build.envVariables` YAML** (to compose a derived var that the bundler consumes) reference the project var directly without prefix:
+**In `build.envVariables` / `run.envVariables` YAML** (to forward a project var under a framework-conventional name) reference it directly without prefix:
```yaml
build:
envVariables:
- VITE_API_URL: ${API_URL} # project var API_URL read as-is, NO RUNTIME_ prefix
+ VITE_API_URL: ${API_URL} # project var API_URL read as-is
+run:
+ envVariables:
+ CORS_ALLOWED_ORIGIN: ${FRONTEND_URL} # forwarded under a different name
```
-**In `run.envVariables` YAML** (to forward a project var under a framework-conventional name without creating a shadow), reference directly without prefix:
+To **override** a project variable for one service, define a service-level variable with the same key and a DIFFERENT VALUE (not a reference to the project var):
```yaml
run:
envVariables:
- CORS_ALLOWED_ORIGIN: ${FRONTEND_URL} # project var FRONTEND_URL forwarded under a different name
+ LOG_LEVEL: debug # overrides project-level LOG_LEVEL for this service
```
-**DO NOT** re-reference an auto-injected variable under its SAME name — that's a self-shadow loop. Applies to BOTH project-level vars AND cross-service vars:
+### Self-Shadow Trap — same name on both sides
-```yaml
-envVariables:
- PROJECT_NAME: ${PROJECT_NAME} # project-level self-shadow
- API_URL: ${API_URL} # project-level self-shadow
- db_hostname: ${db_hostname} # cross-service self-shadow
- queue_user: ${queue_user} # cross-service self-shadow
-```
+Writing `varname: ${varname}` (the left key identical to the source on the right) is always wrong:
-All four resolve to the literal string `${VAR_NAME}` inside the container — the framework tries to connect to `"${db_hostname}:5432"` and crashes. The fix is to delete those lines entirely — the platform already injects the real value as an OS env var.
-
-To **override** a project variable for one service, define a service-level variable with the same key and a DIFFERENT VALUE (not a reference to the project var):
```yaml
run:
envVariables:
- LOG_LEVEL: debug # overrides project-level LOG_LEVEL for this service
+ API_URL: ${API_URL} # project-level self-shadow
+ db_hostname: ${db_hostname} # cross-service self-shadow
```
+The interpolator sees the service-level variable of that name first, can't recurse back to the inherited/referenced value, and the OS env var resolves to the literal string `${varname}` — the app then connects to `"${db_hostname}:5432"` and crashes.
+
+- For a **project var** you only want to read: delete the line — it already auto-inherits.
+- For a **cross-service** value: use a **different** left-hand name (`DB_HOST: ${db_hostname}`), never the same name.
+
### Typical pattern: project-level URL constants for dual-runtime recipes
-Dual-runtime recipes (frontend SPA + backend API on the same platform) use project-level URL constants as the single source of truth for cross-service URLs. The constants are derived from `${zeropsSubdomainHost}` (a platform-generated project-scope env var present from project creation) and the services' known hostnames:
+Dual-runtime recipes (frontend SPA + backend API) use project-level URL constants as the single source of truth for cross-service URLs, derived from `${zeropsSubdomainHost}` (a platform-generated project-scope var present from project creation):
```yaml
project:
@@ -15355,14 +15313,14 @@ project:
FRONTEND_URL: https://appstage-${zeropsSubdomainHost}.prg1.zerops.app
```
-The platform resolves `${zeropsSubdomainHost}` when injecting the value into services at container start. The frontend consumes `API_URL` via plain `${API_URL}` in `build.envVariables` (baking it into the bundle at compile time) — **no `RUNTIME_` prefix**. The API consumes `FRONTEND_URL` via plain `${FRONTEND_URL}` in `run.envVariables` (for CORS allow-list). The same names must be set on the workspace project via `zerops_env project=true action=set` after provision, so workspace verification doesn't see literal `${FRONTEND_URL}` strings.
+The frontend consumes `API_URL` via plain `${API_URL}` in `build.envVariables` (baked into the bundle at compile time). The API consumes `FRONTEND_URL` via plain `${FRONTEND_URL}` in `run.envVariables` (CORS allow-list). Set the same names on the workspace project via `zerops_env project=true action=set` after provision.
## Secret Variables
- Defined via GUI, import.yml `envSecrets`, or `dotEnvSecrets`
-- **Write-only after creation** -- values masked in GUI, cannot be read back via API
-- Can be updated without redeploy, but service **must be restarted**
-- Overridden by basic (zerops.yml) variables with the same key
+- **Read is privilege-gated** -- masked in GUI; via API an admin/write token returns the value verbatim, a read-only token returns `REDACTED` (keyed on `sensitive=true`). In-container the value is plaintext (the app needs it). Project-level `sensitive=true` does NOT persist — only service-level is a true secret surface.
+- Can be updated without redeploy, but the service **must be restarted** to pick it up.
+- Overridden by yaml-baked `run.envVariables` with the same key (yaml owns the key).
### dotEnvSecrets
@@ -15405,22 +15363,22 @@ run:
## Restart Requirement
-Env var changes (secret or project) take effect only on container start. The running process does **not** receive updated values.
+An env-store change (secret or project) propagates to the container in ~5–10s without a redeploy, but the **running process keeps its boot-time environ** — only newly-spawned processes see it.
-**DO NOT** expect hot-reload of env vars. After changing secrets or project vars in GUI, **restart the service**. For zerops.yml `envVariables` changes, a **full redeploy** is required.
+**DO NOT** expect hot-reload of env vars. After changing secrets or project vars, **restart the service** (not reload — reload does not re-read env for the running process; PHP-FPM keeps its boot config). For `zerops.yml` `run.envVariables` changes, a **full redeploy** is required (they are baked into the app version).
## System-Generated Variables
-Zerops auto-generates variables per service (e.g., `hostname`, `PATH`, DB connection strings). Cannot be deleted. Some read-only (`hostname`), others editable (`PATH`). Can be referenced by other services using `${hostname_varname}`.
+Zerops auto-generates variables per service (e.g., `hostname`, `PATH`, DB connection strings). Cannot be deleted. Some read-only (`hostname`), others editable (`PATH`). Reference them from another service with an explicit `${hostname_varname}`.
## Common Mistakes
-- **DO NOT** re-reference auto-injected vars under their own name — self-shadow loop. Applies to BOTH project-level (`API_URL: ${API_URL}`) AND cross-service (`db_hostname: ${db_hostname}`, `queue_user: ${queue_user}`).
-- **DO NOT** declare cross-service vars you only want to READ — they are already in the container's OS env. Read via `process.env.db_hostname` / `getenv('db_hostname')` directly. Declare in `run.envVariables` only to RENAME (e.g. `DB_HOST: ${db_hostname}`) or to set mode flags.
-- **DO NOT** forget restart after GUI/API env changes — process won't see new values
-- **DO NOT** expect `envReplace` to recurse subdirectories — it does not
-- **DO NOT** rely on reading secret values back — they are write-only after creation
-- **DO NOT** create both secret and basic vars with same key — basic silently wins
+- **DO NOT** expect a sibling's vars to appear automatically under default `service` isolation — reference them explicitly as `${hostname_varname}` in `run.envVariables` (the bare `_KEY` injected form is `none`-only legacy).
+- **DO NOT** re-reference a var under its SAME name -- self-shadow loop. Project vars auto-inherit (read directly); cross-service uses a DIFFERENT left-hand name (`DB_HOST: ${db_hostname}`).
+- **DO NOT** set a secret/service var on a key already in `run.envVariables` -- rejected (`userDataDuplicateKey`); the yaml owns the key, edit yaml + redeploy.
+- **DO NOT** assume secret values are unreadable -- API read is privilege-gated (admin verbatim, read-only `REDACTED`), not unconditionally write-only.
+- **DO NOT** forget restart after GUI/API env changes -- the running process won't see new values.
+- **DO NOT** expect `envReplace` to recurse subdirectories -- it does not.
----------------------------------------
@@ -15628,7 +15586,7 @@ http://postgres:5432
- Service discovery is automatic — no manual network config
- VPN uses same hostnames: `http://api:3000` from local machine (both `api` and `api.zerops` resolve — VPN sets up DNS search domain)
-**Cross-service env vars**: prefix with hostname — e.g., `app_API_TOKEN`. Zerops auto-generates connection vars for managed services.
+**Cross-service env vars**: under the default `envIsolation=service`, reference a sibling's var explicitly as `${hostname_varname}` in `run.envVariables` (e.g. `${app_API_TOKEN}`) — siblings are NOT auto-injected. The bare `_KEY` injected form only appears under legacy `envIsolation=none`. Zerops auto-generates connection vars for managed services — reference them the same way (`${db_*}`).
**DO NOT** use `https://` for service-to-service calls — SSL terminates at the L7 balancer, internal network is already isolated.
@@ -16209,7 +16167,7 @@ Zerops offers three public access methods: zerops.app subdomains (dev only, 50MB
- **Not for production** — use for development/testing only
- Auto-provisioned SSL
- Pre-configure via import YAML: `enableSubdomainAccess: true` (works for all runtime/web types)
-- **Activate routing via API:** `zerops_subdomain enable` (only works on deployed/ACTIVE services) — call once after the first deploy of each new service, even if `enableSubdomainAccess: true` was set in import. Import pre-configures routing but does NOT activate L7 balancer; without the explicit enable call, the subdomain returns 502. Re-deploys do NOT deactivate it. Use `zerops_discover` to check current status and get the URL (`subdomainEnabled` + `subdomainUrl` fields).
+- **Activate routing:** `zerops_deploy` **auto-enables** the subdomain on the first deploy for eligible service modes (dev/stage/simple/standard/local-stage) and waits HTTP-ready — the deploy response carries `subdomainAccessEnabled: true` and the URL. Use `zerops_subdomain enable` only as an explicit recovery/ops command if auto-enable was skipped (a worker / non-HTTP service, or launch-production which deliberately opts out in favor of a custom domain). Import's `enableSubdomainAccess: true` pre-configures intent; deploy activates the L7 balancer. Re-deploys do NOT deactivate it. Use `zerops_discover` to check current status and get the URL (`subdomainEnabled` + `subdomainUrl` fields).
- **Port-specific subdomains**: If HTTP ports are defined in zerops.yml, each port gets its own subdomain: `{hostname}-{subdomainHost_prefix}-{port}.{subdomainHost_rest}`. Example: hostname `appdev`, subdomainHost `1df2.prg1.zerops.app`, port 3000 → actual URL `https://appdev-1df2-3000.prg1.zerops.app`. Port 80 omits the port suffix: `https://appdev-1df2.prg1.zerops.app`
- **Internal network fallback**: Every service is accessible internally via `http://{hostname}:{port}` (e.g., `http://appdev:3000`). Use this to verify the app is running when subdomain access is uncertain — `curl http://appdev:3000/health` from the ZCP container or any other service in the project
- Works for: nodejs, static, nginx, go, python, php, java, rust, dotnet, and all other runtime types
@@ -16869,7 +16827,7 @@ Fully managed S3 compatible storage running on a separate infrastructure and per
- [zCLI](/references/cli)
- [zerops.yaml](/zerops-yaml/specification)
-- [Import file](/references/import)
+- [Import YAML](/references/import)
## Feature highlights
@@ -25983,6 +25941,10 @@ Direct IP Access uses [pgBouncer](https://www.pgbouncer.org/) for connection poo
Internally, port `5432` is available without SSL (and port `5433` for reads in HA mode). Externally, connections are secured with TLS through pgBouncer (port `6432`) before being routed to your PostgreSQL service. The read replica port is not available for external connections.
+:::tip Trusting the TLS certificate
+The TLS certificate served on port `6432` is signed by the Zerops Certificate Authority. To verify it from outside Zerops, download and trust the [Zerops CA](/references/networking/zerops-ca) — e.g. `psql "... sslmode=verify-full sslrootcert=./zerops-ca.pem"`.
+:::
+
#### Enable external access
1. Navigate to your PostgreSQL service in the Zerops GUI and choose the **Public Access through IP Addresses** section
@@ -28192,6 +28154,498 @@ For advanced configurations or custom requirements:
- Join our [Discord community](https://discord.gg/zeropsio)
- Contact support via [email](mailto:support@zerops.io)
+----------------------------------------
+
+# Quickstart
+
+
+With this guide, we'll go from zero to a live app with a managed database, a public URL, and auto-deploy on every git push. Takes about 5 minutes.
+
+Here's what we're building together: a page with a button that says **"I followed the Zerops quickstart"**. Every developer who finishes this guide and clicks it gets counted. It's a real app: Express backend, PostgreSQL database, static frontend, all running on **Zerops**.
+
+**See it live before you build it:** [app-25be-3000.prg1.zerops.app](https://app-25be-3000.prg1.zerops.app/)
+[Video: /vids/quickstart-app.webm](/vids/quickstart-app.webm)
+
+:::info Two ways to use this guide
+**Just want to see how Zerops works?** Follow along as-is. The feedback app covers everything: frontend, backend, managed database, private networking, auto-deploy.
+
+**Already have an app?** Pick a recipe matching your stack in Step 1 instead of Node.js. The steps are identical. Then in Step 5, replace the feedback app code with your own. The `zerops.yml` structure stays the same.
+:::
+
+:::tip Before we start
+Sign up at [app.zerops.io](https://app.zerops.io). You get $15 in promo credits on signup, no credit card needed. Verify your account with a $10 payment and get an additional $50, bringing your total to $65 in credits. A simple app with a database costs roughly $3-5/month, so credits go a long way.
+:::
+
+---
+
+## 1. Deploy the recipe
+
+Go to [app.zerops.io/recipes](https://app.zerops.io/recipes). No account needed, the recipes page works even when you're not logged in.
+
+For this guide, find and click **Node.js**. You'll see **Node.js Hello World**, a Node.js app with Express connected to a PostgreSQL database.
+
+Hit **Deploy nodejs-hello-world-small-prod**. If you're not signed in yet, Zerops creates your account and kicks off the deploy in the same step.
+
+:::info What's a recipe?
+A recipe is a working app with infrastructure already configured: managed database, environment variables, `zerops.yaml`, everything connected. It's a correct starting point, not a finished product. We'll swap the code out in Step 5.
+:::
+
+:::note Want a different stack?
+Everything in this guide works the same way for Next.js, Python, Go, Laravel, and more. Just pick the recipe that matches your stack instead. The steps are identical.
+:::
+
+---
+
+## 2. Watch it build
+
+After hitting Deploy, you'll land on the dashboard. On the right side you'll see a pipeline already running.
+
+It goes through these steps in real time:
+
+1. Initializing build container
+2. Running build commands from `zerops.yaml`
+3. Creating app version and upgrading service
+4. Done
+
+:::tip Good to know
+The build container is **temporary and free**. Zerops spins it up, runs your build, saves the output, and deletes it. You're only billed for the running app.
+:::
+
+Once the pipeline finishes, your app is live.
+
+---
+
+## 3. See what got created
+
+Click into your new project. You'll see:
+
+- **app**: your Node.js service, already running
+- **db**: a managed PostgreSQL database, already running
+- **Project core**: load balancer, firewall, logger, all managed by Zerops
+
+All of these are already talking to each other on a private network. Nothing to configure.
+
+:::tip Coming from Vercel and Supabase?
+You're probably used to copying a long database URL and pasting it as an environment variable. On Zerops, services talk to each other by hostname. `DB_HOST` is just `db`, not a URL. You still set credentials in `zerops.yaml`, Zerops fills in the values. No connection strings to manage.
+:::
+
+---
+
+## 4. Open your live app
+
+The Zerops subdomain is already enabled when you deploy from a recipe. Click into your **app** service and open the URL. It looks something like `app-2437-3000.prg1.zerops.app`.
+
+The default recipe app will be there. Next step, we replace it with the feedback app.
+
+When you're ready for production, point a custom domain at your app. Zerops handles the SSL certificate automatically.
+
+---
+
+## 5. Swap in the feedback app
+
+Clone the recipe repo and open it in your editor:
+
+```bash
+git clone https://github.com/zeropsio/recipe-nodejs
+cd recipe-nodejs
+npm install
+```
+
+The repo uses TypeScript. You only need to touch two files: `src/app.ts` and `src/db.ts`. Leave `src/index.ts` and `src/config.ts` exactly as they are.
+
+**Replace `src/db.ts`** with this:
+
+```ts
+
+export const connectDB = async () => {
+ const client = new Client({
+ host: config.db.host,
+ port: config.db.port,
+ user: config.db.username,
+ password: config.db.password,
+ database: config.db.database,
+ });
+
+ await client.connect();
+
+ await client.query(`
+ CREATE TABLE IF NOT EXISTS clicks (
+ id SERIAL PRIMARY KEY,
+ clicked_at TIMESTAMPTZ DEFAULT NOW()
+ )
+ `);
+
+ return client;
+};
+```
+
+**Replace `src/app.ts`** with this:
+
+```ts
+
+const app = express();
+
+app.use(express.static(path.join(__dirname, '../public')));
+
+app.get('/count', async (_, res) => {
+ const client = await connectDB();
+ const result = await client.query('SELECT COUNT(*) FROM clicks');
+ await client.end();
+ res.json({ count: parseInt(result.rows[0].count) });
+});
+
+app.post('/click', async (_, res) => {
+ const client = await connectDB();
+ await client.query('INSERT INTO clicks DEFAULT VALUES');
+ const result = await client.query('SELECT COUNT(*) FROM clicks');
+ await client.end();
+ res.json({ count: parseInt(result.rows[0].count) });
+});
+
+app.get('/status', (_, res) => {
+ res.status(200).send({ status: 'UP' });
+});
+
+export default app;
+```
+
+**Create a `public/` folder** at the repo root and add `public/index.html`:
+
+```html
+
+
+
+
+
+ Zerops Quickstart
+
+
+
+
+
+ zerops
+
+
You made it. 🎉
+
+ You just deployed a real app: managed database, private network,
+ auto-deploy. Let us know you made it through.
+
+
+
+ ...
+
+
+
+
+
+ Node.js 20
+ PostgreSQL 16
+ Zerops
+
+
+
+
+
+```
+
+The `zerops.yml` already exists in the repo. Update `deployFiles` to include the `public` folder:
+
+```yaml
+zerops:
+ - setup: app
+ build:
+ base: nodejs@20
+ prepareCommands:
+ - npm install -g typescript
+ buildCommands:
+ - npm i
+ - npm run build
+ deployFiles:
+ - ./dist
+ - ./node_modules
+ - ./public
+ - ./package.json
+ run:
+ base: nodejs@20
+ ports:
+ - port: 3000
+ httpSupport: true
+ envVariables:
+ NODE_ENV: production
+ DB_NAME: db
+ DB_HOST: db
+ DB_USER: db
+ DB_PASS: ${db_password}
+ start: npm run start:prod
+ healthCheck:
+ httpGet:
+ port: 3000
+ path: /status
+```
+
+Before pushing, point the repo at your own GitHub remote:
+
+```bash
+git remote set-url origin https://github.com/your-username/your-repo.git
+git push -u origin main
+```
+
+Then move on to Step 6 to connect it to Zerops.
+
+:::note Want to build something else instead?
+Skip the feedback app. Clone the repo, keep the `zerops.yml` as-is, and replace `src/app.ts` with your own routes. The DB connection, build pipeline, and env variables all stay the same.
+:::
+
+---
+
+## 6. Connect GitHub and auto-deploy
+
+1. Click into your **app** service
+2. Scroll down to **Pipelines & CI/CD settings**
+3. Click **GitHub** to connect your repo
+4. Select your repo and set **Trigger on** to **Push to Branch**, pick `main`
+5. In the **"Which `setup` from zerops.yml to use"** field, type `app`
+6. Click **Activate pipeline trigger**
+
+That's it. Every push to main now builds and deploys automatically. Zero downtime, Zerops runs the new version alongside the old one, waits for a health check, then switches traffic over.
+
+You can also trigger deploys manually with the Zerops CLI: `zcli push`.
+
+---
+
+## You're live 🎉
+
+Open your app URL. You should see the feedback button app: a big button, a live click count pulled from the database, all running on Zerops.
+
+Here's what's running:
+
+- A real app on production infrastructure
+- A managed PostgreSQL database with no setup, no connection strings, no SDK
+- Auto-deploy on every git push with zero downtime
+- All services on a private network, secure by default
+- Full Linux containers you can SSH into and install anything on
+
+None of the infrastructure needed manual configuration.
+
+---
+
+## If something breaks
+
+Got a 502 or an app crash on startup? Start here.
+
+**Check the runtime logs first.** Dashboard, click your app service, click the three-dot menu, then **Runtime log**. The error will be there, usually in the last few lines.
+
+Two things come up most often on a first deploy:
+
+:::tip Debug locally with VPN
+Install zcli first (see [CLI reference](/references/cli)), then run `zcli vpn up [your-project-id]` and your laptop joins the project's private network. You can connect to `db:5432` directly from your local machine using TablePlus, psql, or any database client. Disable SSL when connecting over VPN, security is handled by the tunnel itself. If `db` doesn't resolve, try `db.zerops` instead.
+:::
+
+---
+
+## What's next
+
+- **[SSH into your container](/references/networking/ssh)**: `zcli service shell [service-name]` for full Linux access
+- **[Custom domain](/references/networking/public-access)**: add your domain, SSL is automatic
+- **[Autoscaling](/features/scaling)**: set min and max CPU and RAM, Zerops scales within that range automatically
+- **[Add more services](/features/infrastructure)**: queues, search engines, object storage, just add them to your project
+- **[Try ZCP](/zcp/quickstart)**: Zerops' AI agent that can deploy, debug, and operate your project
+
+:::note Stuck?
+Jump into the [Zerops Discord](https://docs.zerops.io/discord). The community is active and the team is there.
+:::
+
+
----------------------------------------
# Rust > How To > Build Pipeline
@@ -32156,6 +32610,10 @@ Our HA implementation uses a unique approach to ensure high availability while m
Be aware that replica data may lag slightly behind the master due to asynchronous replication.
:::
+:::tip Trusting the TLS certificate
+The certificates served on the TLS ports (`6380` and `7001`) are signed by the Zerops Certificate Authority. To verify them from outside Zerops, download and trust the [Zerops CA](/references/networking/zerops-ca) — e.g. `redis-cli --tls --cacert ./zerops-ca.pem -h -p 6380`.
+:::
+
## Learn More
- [Official Valkey Documentation](https://valkey.io/docs) - Comprehensive guide to Valkey features
@@ -32395,7 +32853,7 @@ Use these definitions when a page, workflow status, agent handoff, or policy nee
**Remote setup** - the `zcp` binary running inside a Zerops `zcp@1` service.
-**Include Coding Agent** - remote setup option that adds the bundled agent CLI, currently Claude Code, and preconfigures it to use ZCP MCP tools.
+**Include Coding Agent** - remote setup option that adds a bundled agent CLI (Claude Code, Codex, Antigravity, or Grok Build) and preconfigures it to use ZCP MCP tools.
**Cloud IDE** - browser-based VS Code served by remote setup.
@@ -32507,16 +32965,51 @@ Use these definitions when a page, workflow status, agent handoff, or policy nee
# Zcp > Overview
-:::info Public preview
-ZCP MCP is a public preview and is under active development. If you hit a bug, confusing behavior, or a missing workflow, please report it on [Discord](/discord); feedback from real projects is especially useful.
-:::
-
This section covers, in order:
-- **How a run unfolds.** [Quickstart](/zcp/quickstart) for hands-on; [How it works](/zcp/concept/how-it-works) for the work loop.
-- **Where the agent runs.** [Remote or local setup](/zcp/setup/choose-workspace), [Trust model](/zcp/security/trust-model), and [Production boundary](/zcp/security/production-policy).
-- **What you decide while working.** [Build and ship](/zcp/workflows/build-with-zcp), [Package a running service](/zcp/workflows/package-running-service), [Promote to production](/zcp/workflows/promote-to-production).
-- **Exact labels when they matter.** [Workflows in depth](/zcp/reference/agent-workflow), [ZCP MCP tools](/zcp/reference/mcp-operations), [Troubleshooting](/zcp/reference/troubleshooting), [Glossary](/zcp/glossary).
+
+
+
+
+GET STARTED
+
+
Quickstart and concept
+
+[Quickstart](/zcp/quickstart) for hands-on; [How it works](/zcp/concept/how-it-works) for the work loop.
+
+
+
+
+
+SETUP
+
+
Remote or local workspace
+
+[Remote or local setup](/zcp/setup/choose-workspace), [Trust model](/zcp/security/trust-model), and [Production boundary](/zcp/security/production-policy).
+
+
+
+
+
+WORKFLOWS
+
+
Build, package, promote
+
+[Build and ship](/zcp/workflows/build-with-zcp), [Package a running service](/zcp/workflows/package-running-service), [Promote to production](/zcp/workflows/promote-to-production).
+
+
For the broader feature concept — why coding agents need real project infrastructure rather than a sandbox or generated artifact — start with [Infrastructure for Coding Agents](/features/coding-agents).
@@ -32526,13 +33019,49 @@ Your prompt can stay about the product. Name the stack, runtime layout, acceptan
## What the agent gets
-**Current state.** Services, runtime layout, managed dependencies, env-var keys and references, logs, events, deploy history, verification state, and saved work state.
+
+
+
+
+STATE
-**Zerops operations.** Project-scoped tools for discovering services, changing env vars, managing runtimes, deploying, verifying, scaling, public access, and delivery setup.
+### Current state
-**Workflow.** The generated instructions combine service setup and app development: inspect state, choose the runtime target, use or create services, wire code and `zerops.yaml`, deploy, verify, and choose delivery. The Zerops work stays behind the product task instead of becoming another checklist.
+Services, runtime layout, managed dependencies, env-var keys and references, logs, events, deploy history, verification state, and saved work state.
-**Evidence-based completion.** A build or deploy is not the finish line. A completed app task should end with a working URL, endpoint result, UI proof, or a blocker backed by logs, events, and verification evidence.
+
+
+
+
+CONTROLS
+
+### Zerops operations
+
+Project-scoped tools for discovering services, changing env vars, managing runtimes, deploying, verifying, scaling, public access, and delivery setup.
+
+
+
+
+
+INSTRUCTIONS
+
+### Workflow
+
+The generated instructions combine service setup and app development: inspect state, choose the runtime target, use or create services, wire code and `zerops.yaml`, deploy, verify, and choose delivery. The Zerops work stays behind the product task instead of becoming another checklist.
+
+
+
+
+
+EVIDENCE
+
+### Evidence-based completion
+
+A build or deploy is not the finish line. A completed app task should end with a working URL, endpoint result, UI proof, or a blocker backed by logs, events, and verification evidence.
+
+
+
+
## What you no longer have to script
@@ -32554,7 +33083,7 @@ To start, add remote setup in Zerops or initialize local setup beside your edito
## Your agent, credentials, and workspace
-**Agent account.** Remote setup can include a bundled agent CLI, currently Claude Code, already configured for MCP. Zerops wires the agent to the tools; you still authenticate with your own subscription login or API credentials.
+**Agent account.** ZCP supports multiple coding agents including Claude Code (Anthropic), Codex (OpenAI), Antigravity, and Grok Build. Remote setup can bundle one of these, already configured for MCP. Zerops wires the agent to the tools; you still authenticate with your own subscription login or API credentials.
**Zerops token.** The MCP server connects through `ZCP_API_KEY`, a Zerops token limited to one project. Remote setup gets it from the platform; local setup reads it from `.mcp.json`. Token details live in [Tokens and credentials](/zcp/security/tokens-and-project-access).
@@ -32574,7 +33103,9 @@ This section is not a replacement for Zerops platform references. The Zerops [bu
# Zcp > Quickstart
-Use this when you want the fastest hands-on ZCP loop: deploy an **AI Agent** recipe, authorize Claude Code, open Browser VS Code, and ask for one product change.
+Use this when you want the fastest hands-on ZCP loop: deploy an **AI Agent** recipe, authorize your coding agent, open Browser VS Code, and ask for one product change.
+
+ZCP supports multiple coding agents including Claude Code (Anthropic), Codex (OpenAI), Antigravity, and Grok Build. The screenshots below use Claude Code as the walkthrough example.
Some [Zerops recipes](https://app.zerops.io/recipes) include an **AI Agent** environment. That preset creates app services, managed services, the `zcp@1` workspace, Browser VS Code, and bundled agent wiring in one deploy.
@@ -32583,7 +33114,7 @@ This quickstart uses [Laravel showcase](https://app.zerops.io/recipes/laravel-sh
## Prerequisites
- A Zerops account with permission to create a project.
-- A Claude Code subscription login or API authentication. Zerops wires Claude Code to ZCP, but your agent subscription or model credentials stay yours.
+- A subscription login or API credentials for your chosen coding agent (Claude Code, Codex, Antigravity, or Grok Build). Zerops wires the agent to ZCP, but your agent subscription or model credentials stay yours.
## 1. Choose the AI Agent recipe
@@ -32595,23 +33126,23 @@ This quickstart uses [Laravel showcase](https://app.zerops.io/recipes/laravel-sh
The deploy creates app runtimes, managed dependencies, and a `zcp@1` workspace. In this recipe it appears as the `zcp` service. The agent, terminal, and browser IDE run there. App code still deploys to the app runtimes, not to `zcp`.
-## 2. Authorize Claude Code
+## 2. Authorize your coding agent
-When provisioning finishes, the dashboard opens the Claude Code authentication flow. Use your own Claude Code subscription login or API credentials.
+When provisioning finishes, the dashboard opens the authentication flow for your bundled agent. If you are using Claude Code (as in the screenshots below), use your own Claude Code subscription login or API credentials.
-This is separate from `ZCP_API_KEY`, the Zerops token used by ZCP. Your Claude login or API key is used only by the bundled agent.
+This is separate from `ZCP_API_KEY`, the Zerops token used by ZCP. Your agent login or API key is used only by the bundled agent.
If you close the prompt, open the `zcp` service in the dashboard. Its panel shows the browser workspace, web terminal, SSH access, desktop editor access, and agent authorization state.
## 3. Open the workspace
-After authentication, continue into **Browser VS Code**. The workspace opens with files, ZCP configuration, terminal access, and the Claude Code panel.
+After authentication, continue into **Browser VS Code**. The workspace opens with files, ZCP configuration, terminal access, and your coding agent panel (the Claude Code panel in the screenshots below).
You are now inside the remote workspace. The agent can read live state, use the MCP tools, reach private services, and deploy app changes to the runtimes created by the recipe.
## 4. Ask for a product outcome
-In Claude Code, ask for the app behavior in natural language. A good first prompt is intentionally short:
+In your coding agent, ask for the app behavior in natural language. A good first prompt is intentionally short:
```text
Build a task board for my team.
@@ -33559,7 +34090,7 @@ A remote workspace puts the agent, terminal, and optional browser IDE inside Zer
The `zcp@1` service runs the same `zcp` binary used by local setup, but broad shell permissions and private service access stay in a clean Zerops service instead of on your laptop.
-Use remote setup when you want the default workspace, a safer boundary for broad agent permissions, or a preconfigured environment with Claude Code and Browser VS Code.
+Use remote setup when you want the default workspace, a safer boundary for broad agent permissions, or a preconfigured environment with a bundled coding agent and Browser VS Code.
App code still deploys to your app runtime services. The `zcp` service is the workspace and control surface; it is not the application runtime.
@@ -33569,7 +34100,7 @@ Taking over is straightforward in this setup. You open the same workspace, termi
- **`zcp@1` workspace service.** Runs ZCP inside Zerops and gives the agent project-scoped operations.
- **Platform-injected `ZCP_API_KEY`.** Zerops injects the token into the workspace; you normally do not set it by hand.
-- **Bundled Claude Code when enabled.** The **Include Coding Agent** option installs and preconfigures Claude Code. You authenticate with your own Claude subscription login or API key.
+- **Bundled coding agent when enabled.** The **Include Coding Agent** option installs and preconfigures one of the supported agents: Claude Code (Anthropic), Codex (OpenAI), Antigravity, or Grok Build. You authenticate with your own subscription login or API credentials.
- **Browser VS Code when enabled.** The **Cloud IDE** option gives you a browser editor, terminal, and a place to supervise or take over the agent session.
- **Private networking.** The workspace can reach managed services by hostname without laptop VPN.
- **Open workspace model.** You can add other agent CLIs, private MCP servers, helper processes, dotfiles, package installs, or a derived team image.
@@ -33580,7 +34111,7 @@ For the local alternative, see [Run locally](/zcp/setup/local-agent-bridge). For
### First-time trial
-Use the [Quickstart](/zcp/quickstart) when you want the guided recipe route. It covers the recipe catalog, **AI Agent** environment, Claude Code authentication, Browser VS Code, first product prompt, and proof.
+Use the [Quickstart](/zcp/quickstart) when you want the guided recipe route. It covers the recipe catalog, **AI Agent** environment, coding agent authentication, Browser VS Code, first product prompt, and proof.
After provisioning, continue with a product prompt in [Build and ship](/zcp/workflows/build-with-zcp).
@@ -33588,7 +34119,7 @@ After provisioning, continue with a product prompt in [Build and ship](/zcp/work
Use this when you want a guided stack baseline for development or staging. A recipe with an **AI Agent** environment creates app services, managed services, and the `zcp@1` workspace together.
-Keep **Coding Agent** enabled when you want bundled Claude Code. Keep **Cloud IDE** enabled when you want Browser VS Code.
+Keep **Coding Agent** enabled when you want a bundled coding agent. Keep **Cloud IDE** enabled when you want Browser VS Code.
### New Zerops setup with remote setup enabled
@@ -33597,7 +34128,7 @@ Use this when you want blank services or a custom stack.
1. Open [Add new project](https://app.zerops.io/dashboard/project-add).
2. Enter the project name, region, and tags.
3. Enable the `zcp@1` remote setup service.
-4. Keep **Include Coding Agent** enabled if you want bundled Claude Code.
+4. Keep **Include Coding Agent** enabled if you want a bundled coding agent.
5. Keep **Cloud IDE** enabled if you want browser VS Code.
6. Create the project.
@@ -33618,9 +34149,9 @@ For a returning remote workspace, open the existing `zcp` service:
1. Open the project in the [Zerops dashboard](https://app.zerops.io/).
2. Open the `zcp` service.
3. Use **Browser VS Code** when **Cloud IDE** is enabled.
-4. Complete the Claude Code login or API-token flow if prompted.
+4. Complete your coding agent login or API-token flow if prompted (Claude Code, Codex, Antigravity, or Grok Build).
-After authentication, Claude Code is connected to ZCP and ready to work from the Browser VS Code terminal. If the workspace was already authorized, use the same route to resume, supervise, or take over work.
+After authentication, your coding agent is connected to ZCP and ready to work from the Browser VS Code terminal. If the workspace was already authorized, use the same route to resume, supervise, or take over work.
First load can take a minute while the image, Cloud IDE, and bundled agent finish starting. If the page opens before the service is ready, wait until the service is running and reload.
@@ -33632,7 +34163,7 @@ Editors that support remote development can connect to the workspace or runtime
This keeps the agent and private network inside Zerops while letting you use a desktop editor UI. Broader editor patterns live in [Local & Remote Development](/features/local-remote-development#native-ide-over-ssh).
-You can also install another agent CLI or additional MCP servers inside the `zcp` service. The bundled Claude Code flow is a convenience, not a closed product boundary.
+You can also install another agent CLI or additional MCP servers inside the `zcp` service. The bundled agent flow is a convenience, not a closed product boundary.
## Advanced customization guardrails
@@ -33645,7 +34176,7 @@ Tools installed inside the `zcp` service may see workspace environment variables
| Agent workspace | The `zcp@1` service: agent CLI, browser VS Code, shell tools, MCP servers, helper processes, dotfiles. |
| App code deploys | Your app runtime services; not the `zcp` workspace service. |
| `ZCP_API_KEY` | Injected by Zerops into the `zcp` workspace. |
-| Agent account | Your Claude subscription login or model API credential. Zerops wires the agent to ZCP, but the agent account remains yours. |
+| Agent account | Your agent subscription login or model API credential. Zerops wires the agent to ZCP, but the agent account remains yours. |
| Git credentials | Configured inside the workspace when the agent should commit or push from remote setup. |
| Production release | A separate production project and release process. |
| Production release | A separate production project and release process. |
@@ -33685,7 +34216,7 @@ Use it when the agent should work next to local files, local data, your desktop
[Remote setup](/zcp/setup/hosted-workspace) is the safer default when the agent does not need local files or tools. Use local setup when local control is the point.
-:::warning Public preview
+:::warning Local setup maturity
Local setup has more moving parts than remote setup and may change faster. The binary install path, `.mcp.json` shape, and files written by `zcp init` are still settling between releases.
:::
@@ -35181,5 +35712,43 @@ For more detailed information on specific configurations, refer to the runtime-s
*Need help? Join our [Discord community](https://discord.gg/zeropsio).*
+## Editor support (JSON Schema)
+
+Zerops publishes an official [JSON Schema ↗](https://json-schema.org/) for `zerops.yaml`:
+
+```
+https://api.app-prg1.zerops.io/api/rest/public/settings/zerops-yml-json-schema.json
+```
+
+With the schema attached, your editor gives you:
+
+- **Autocomplete** for every key and nested field
+- **Inline documentation** on hover
+- **Validation** — typos, wrong types, and missing required fields are flagged as you type
+- **Enum suggestions** for fields like `base` or `cache`
+
+### Auto-detection via SchemaStore
+
+The schema is registered with [SchemaStore ↗](https://www.schemastore.org/), so most YAML-aware editors apply it automatically — no setup required — when the file is named:
+
+- `zerops.yml`
+- `zerops.yaml`
+
+This covers VS Code (with the [YAML extension by Red Hat ↗](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml)), all JetBrains IDEs, and any editor backed by [`yaml-language-server` ↗](https://github.com/redhat-developer/yaml-language-server) (Neovim, Helix, Sublime LSP, …).
+
+### Manual attachment
+
+If your file is named differently, add a modeline at the top:
+
+```yaml
+# yaml-language-server: $schema=https://api.app-prg1.zerops.io/api/rest/public/settings/zerops-yml-json-schema.json
+zerops:
+ - setup: app
+ # ...
+```
+
+The same URL works in any editor that lets you map a schema to a file pattern manually (e.g., `yaml.schemas` in VS Code `settings.json`, or JetBrains' **JSON Schema Mappings** panel).
+
+
----------------------------------------
diff --git a/apps/docs/static/llms.txt b/apps/docs/static/llms.txt
index c1d8591b5..f11f42c6c 100644
--- a/apps/docs/static/llms.txt
+++ b/apps/docs/static/llms.txt
@@ -263,6 +263,7 @@
- [Python > How To > Upgrade](https://docs.zerops.io/python/how-to/upgrade.md)
- [Python > Overview](https://docs.zerops.io/python/overview.md)
- [Qdrant > Overview](https://docs.zerops.io/qdrant/overview.md)
+- [Quickstart](https://docs.zerops.io/quickstart.md)
- [References > Api](https://docs.zerops.io/references/api.md)
- [References > Cli](https://docs.zerops.io/references/cli.md)
- [References > Github Integration](https://docs.zerops.io/references/github-integration.md)
@@ -281,6 +282,7 @@
- [References > Networking > Public Access](https://docs.zerops.io/references/networking/public-access.md)
- [References > Networking > Ssh](https://docs.zerops.io/references/networking/ssh.md)
- [References > Networking > Vpn](https://docs.zerops.io/references/networking/vpn.md)
+- [References > Networking > Zerops Ca](https://docs.zerops.io/references/networking/zerops-ca.md)
- [References > Smtp](https://docs.zerops.io/references/smtp.md)
- [References > Zcli > Commands](https://docs.zerops.io/references/zcli/commands.md)
- [References > Zcli > Configuration](https://docs.zerops.io/references/zcli/configuration.md)
diff --git a/apps/docs/static/vids/quickstart-app.webm b/apps/docs/static/vids/quickstart-app.webm
new file mode 100644
index 000000000..43f55f566
Binary files /dev/null and b/apps/docs/static/vids/quickstart-app.webm differ
diff --git a/apps/docs/static/vids/three-panel-welcome-screen.webm b/apps/docs/static/vids/three-panel-welcome-screen.webm
new file mode 100644
index 000000000..0e4c3a920
Binary files /dev/null and b/apps/docs/static/vids/three-panel-welcome-screen.webm differ
diff --git a/yarn.lock b/yarn.lock
index eb7fea888..cd9a9e762 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3357,6 +3357,84 @@
resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.32.1.tgz#abfeb839d65d0abe923576f34ac08342c25dfa55"
integrity sha512-famxyD5emrGGpFuUlgOP6fVW2h/ZaF405G5KDi3zPHzyjAWys/8W6NAVJtNbkCkhedmvL0xOhvt8feGXyXaw5w==
+"@resvg/resvg-js-android-arm-eabi@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.6.2.tgz#e761e0b688127db64879f455178c92468a9aeabe"
+ integrity sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==
+
+"@resvg/resvg-js-android-arm64@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.6.2.tgz#b8cb564d7f6b3f37d9b43129f5dc5fe171e249e4"
+ integrity sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==
+
+"@resvg/resvg-js-darwin-arm64@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.6.2.tgz#49bd3faeda5c49f53302d970e6e79d006de18e7d"
+ integrity sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==
+
+"@resvg/resvg-js-darwin-x64@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.6.2.tgz#e1344173aa27bfb4d880ab576d1acf1c1648faca"
+ integrity sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==
+
+"@resvg/resvg-js-linux-arm-gnueabihf@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.6.2.tgz#34c445eba45efd68f6130b2ab426d76a7424253d"
+ integrity sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==
+
+"@resvg/resvg-js-linux-arm64-gnu@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.6.2.tgz#30da47087dd8153182198b94fe9f8d994890dae5"
+ integrity sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==
+
+"@resvg/resvg-js-linux-arm64-musl@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.6.2.tgz#5d75b8ff5c83103729c1ca3779987302753c50d4"
+ integrity sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==
+
+"@resvg/resvg-js-linux-x64-gnu@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.6.2.tgz#411abedfaee5edc57cbb7701736cecba522e26f3"
+ integrity sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==
+
+"@resvg/resvg-js-linux-x64-musl@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.6.2.tgz#fe4984038f0372f279e3ff570b72934dd7eb2a5c"
+ integrity sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==
+
+"@resvg/resvg-js-win32-arm64-msvc@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.6.2.tgz#d3a053cf7ff687087a2106330c0fdaae706254d1"
+ integrity sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==
+
+"@resvg/resvg-js-win32-ia32-msvc@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.6.2.tgz#7cdda1ce29ef7209e28191d917fa5bef0624a4ad"
+ integrity sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==
+
+"@resvg/resvg-js-win32-x64-msvc@2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.6.2.tgz#cb0ad04525d65f3def4c8d346157a57976d5b388"
+ integrity sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==
+
+"@resvg/resvg-js@^2.6.2":
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/@resvg/resvg-js/-/resvg-js-2.6.2.tgz#3e92a907d88d879256c585347c5b21a7f3bb5b46"
+ integrity sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==
+ optionalDependencies:
+ "@resvg/resvg-js-android-arm-eabi" "2.6.2"
+ "@resvg/resvg-js-android-arm64" "2.6.2"
+ "@resvg/resvg-js-darwin-arm64" "2.6.2"
+ "@resvg/resvg-js-darwin-x64" "2.6.2"
+ "@resvg/resvg-js-linux-arm-gnueabihf" "2.6.2"
+ "@resvg/resvg-js-linux-arm64-gnu" "2.6.2"
+ "@resvg/resvg-js-linux-arm64-musl" "2.6.2"
+ "@resvg/resvg-js-linux-x64-gnu" "2.6.2"
+ "@resvg/resvg-js-linux-x64-musl" "2.6.2"
+ "@resvg/resvg-js-win32-arm64-msvc" "2.6.2"
+ "@resvg/resvg-js-win32-ia32-msvc" "2.6.2"
+ "@resvg/resvg-js-win32-x64-msvc" "2.6.2"
+
"@rtsao/scc@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8"
@@ -3432,6 +3510,14 @@
resolved "https://registry.yarnpkg.com/@segment/isodate/-/isodate-1.0.3.tgz#f44e8202d5edd277ce822785239474b2c9411d4a"
integrity sha512-BtanDuvJqnACFkeeYje7pWULVv8RgZaqKHWwGFnL/g/TH/CcZjkIVTfGDp/MAxmilYHUkrX70SqwnYSTNEaN7A==
+"@shuding/opentype.js@1.4.0-beta.0":
+ version "1.4.0-beta.0"
+ resolved "https://registry.yarnpkg.com/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz#5d1e7e9e056f546aad41df1c5043f8f85d39e24b"
+ integrity sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==
+ dependencies:
+ fflate "^0.7.3"
+ string.prototype.codepointat "^0.2.1"
+
"@sideway/address@^4.1.5":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5"
@@ -5218,6 +5304,11 @@ base64-arraybuffer@^1.0.2:
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
+base64-js@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
+ integrity sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==
+
baseline-browser-mapping@^2.8.25:
version "2.8.31"
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.8.31.tgz#16c0f1814638257932e0486dbfdbb3348d0a5710"
@@ -5441,6 +5532,11 @@ camelcase@^7.0.1:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048"
integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==
+camelize@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
+ integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
+
caniuse-api@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
@@ -5661,7 +5757,7 @@ color-convert@^2.0.1:
dependencies:
color-name "~1.1.4"
-color-name@^1.0.0, color-name@~1.1.4:
+color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
@@ -5967,11 +6063,31 @@ crypto-random-string@^4.0.0:
dependencies:
type-fest "^1.0.1"
+css-background-parser@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/css-background-parser/-/css-background-parser-0.1.0.tgz#48a17f7fe6d4d4f1bca3177ddf16c5617950741b"
+ integrity sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==
+
+css-box-shadow@1.0.0-3:
+ version "1.0.0-3"
+ resolved "https://registry.yarnpkg.com/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz#9eaeb7140947bf5d649fc49a19e4bbaa5f602713"
+ integrity sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==
+
+css-color-keywords@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
+ integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==
+
css-declaration-sorter@^7.2.0:
version "7.3.0"
resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-7.3.0.tgz#edc45c36bcdfea0788b1d4452829f142ef1c4a4a"
integrity sha512-LQF6N/3vkAMYF4xoHLJfG718HRJh34Z8BnNhd6bosOMIVjMlhuZK5++oZa3uYAgrI5+7x2o27gUqTR2U/KjUOQ==
+css-gradient-parser@^0.0.16:
+ version "0.0.16"
+ resolved "https://registry.yarnpkg.com/css-gradient-parser/-/css-gradient-parser-0.0.16.tgz#5735da0822aef39da9b1960b314792ab542d9bb5"
+ integrity sha512-3O5QdqgFRUbXvK1x5INf1YkBz1UKSWqrd63vWsum8MNHDBYD5urm3QtxZbKU259OrEXNM26lP/MPY3d1IGkBgA==
+
css-line-break@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0"
@@ -6027,6 +6143,15 @@ css-select@^5.1.0:
domutils "^3.0.1"
nth-check "^2.0.1"
+css-to-react-native@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32"
+ integrity sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==
+ dependencies:
+ camelize "^1.0.0"
+ css-color-keywords "^1.0.0"
+ postcss-value-parser "^4.0.2"
+
css-tree@^1.1.2, css-tree@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
@@ -6860,6 +6985,11 @@ elkjs@^0.9.0:
resolved "https://registry.yarnpkg.com/elkjs/-/elkjs-0.9.3.tgz#16711f8ceb09f1b12b99e971b138a8384a529161"
integrity sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==
+emoji-regex@^10.2.1:
+ version "10.6.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.6.0.tgz#bf3d6e8f7f8fd22a65d9703475bc0147357a6b0d"
+ integrity sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==
+
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
@@ -7794,6 +7924,11 @@ feed@^4.2.2:
dependencies:
xml-js "^1.6.11"
+fflate@^0.7.3:
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.7.4.tgz#61587e5d958fdabb5a9368a302c25363f4f69f50"
+ integrity sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==
+
fflate@^0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea"
@@ -8436,6 +8571,11 @@ hermes-parser@^0.25.1:
dependencies:
hermes-estree "0.25.1"
+hex-rgb@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/hex-rgb/-/hex-rgb-4.3.0.tgz#af5e974e83bb2fefe44d55182b004ec818c07776"
+ integrity sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==
+
history@^4.9.0:
version "4.10.1"
resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
@@ -9495,6 +9635,14 @@ lilconfig@^3.0.0, lilconfig@^3.1.1, lilconfig@^3.1.3:
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4"
integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==
+linebreak@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/linebreak/-/linebreak-1.1.0.tgz#831cf378d98bced381d8ab118f852bd50d81e46b"
+ integrity sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==
+ dependencies:
+ base64-js "0.0.8"
+ unicode-trie "^2.0.0"
+
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
@@ -11196,6 +11344,11 @@ package-json@^8.1.0:
registry-url "^6.0.0"
semver "^7.3.7"
+pako@^0.2.5:
+ version "0.2.9"
+ resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+ integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==
+
param-case@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"
@@ -11211,6 +11364,14 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
+parse-css-color@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/parse-css-color/-/parse-css-color-0.2.1.tgz#b687a583f2e42e66ffdfce80a570706966e807c9"
+ integrity sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==
+ dependencies:
+ color-name "^1.1.4"
+ hex-rgb "^4.1.0"
+
parse-entities@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8"
@@ -11752,7 +11913,7 @@ postcss-unique-selectors@^6.0.4:
dependencies:
postcss-selector-parser "^6.0.16"
-postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
+postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
@@ -12748,6 +12909,23 @@ safe-regex-test@^1.0.3, safe-regex-test@^1.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+satori@^0.12.2:
+ version "0.12.2"
+ resolved "https://registry.yarnpkg.com/satori/-/satori-0.12.2.tgz#b0b06ed5eed3cd1b9140777364ba6bd1cb32c37c"
+ integrity sha512-3C/laIeE6UUe9A+iQ0A48ywPVCCMKCNSTU5Os101Vhgsjd3AAxGNjyq0uAA8kulMPK5n0csn8JlxPN9riXEjLA==
+ dependencies:
+ "@shuding/opentype.js" "1.4.0-beta.0"
+ css-background-parser "^0.1.0"
+ css-box-shadow "1.0.0-3"
+ css-gradient-parser "^0.0.16"
+ css-to-react-native "^3.0.0"
+ emoji-regex "^10.2.1"
+ escape-html "^1.0.3"
+ linebreak "^1.1.0"
+ parse-css-color "^0.2.1"
+ postcss-value-parser "^4.2.0"
+ yoga-wasm-web "^0.3.3"
+
sax@^1.2.4:
version "1.4.3"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.3.tgz#fcebae3b756cdc8428321805f4b70f16ec0ab5db"
@@ -13251,16 +13429,7 @@ streamsearch@^1.1.0:
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
-"string-width-cjs@npm:string-width@^4.2.0":
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
-string-width@^4.1.0, string-width@^4.2.0:
+"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -13278,6 +13447,11 @@ string-width@^5.0.1, string-width@^5.1.2:
emoji-regex "^9.2.2"
strip-ansi "^7.0.1"
+string.prototype.codepointat@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz#004ad44c8afc727527b108cd462b4d971cd469bc"
+ integrity sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==
+
string.prototype.includes@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz#eceef21283640761a81dbe16d6c7171a4edf7d92"
@@ -13377,14 +13551,7 @@ stringify-object@^3.3.0:
is-obj "^1.0.1"
is-regexp "^1.0.0"
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
-strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -13682,6 +13849,11 @@ thunky@^1.0.2:
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==
+tiny-inflate@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4"
+ integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==
+
tiny-invariant@^1.0.2:
version "1.3.3"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127"
@@ -14051,6 +14223,14 @@ unicode-property-aliases-ecmascript@^2.0.0:
resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz#301d4f8a43d2b75c97adfad87c9dd5350c9475d1"
integrity sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==
+unicode-trie@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/unicode-trie/-/unicode-trie-2.0.0.tgz#8fd8845696e2e14a8b67d78fa9e0dd2cad62fec8"
+ integrity sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==
+ dependencies:
+ pako "^0.2.5"
+ tiny-inflate "^1.0.0"
+
unified@^10.0.0:
version "10.1.2"
resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df"
@@ -14754,6 +14934,11 @@ yocto-queue@^1.0.0:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.2.tgz#3e09c95d3f1aa89a58c114c99223edf639152c00"
integrity sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==
+yoga-wasm-web@^0.3.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz#eb8e9fcb18e5e651994732f19a220cb885d932ba"
+ integrity sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==
+
zod-to-json-schema@3.24.6:
version "3.24.6"
resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz#5920f020c4d2647edfbb954fa036082b92c9e12d"