# Why nyxory exists Source: https://nyxory.com/docs/background/why-nyxory-exists.md ## The shift We've moved from vibe coding to **agentic engineering**. Writing code stopped being the bottleneck the moment coding agents got good enough to generate working systems on demand. The bottleneck moved one step down: running what those agents produce. That gap has two sides. Builders and business teams can create working software in hours, then wait weeks for a way to ship it. The people accountable for production, from IT to platform to compliance, see software appear faster than they can safely take it in. Today's infrastructure was built for human operators on human timelines; agents hit its walls the moment they leave the IDE, and companies hit them the moment an AI-built app matters. The question has shifted from "can we build it?" to "can we safely run it?" ## The position nyxory is the **independent execution layer for AI-built software**: the runtime where it goes live and keeps running, without human-centric friction in the loop. The product surface speaks MCP. The platform handles everything that doesn't belong in the agent's head: clusters, certs, ingress, scaling. Your agent calls `nyx_brain`, applies the cookbook, and gets a URL back. A deploy button is quickly copied; plenty of platforms have one. The part almost nobody delivers is what comes after: actually operating that software in production, on infrastructure a regulated European company is allowed to trust, with every action on the record. That is the layer nyxory takes accountability for, and it's why the operations record runs through everything in these docs. ## Why it's built this way Every deploy that lands teaches the cookbook something, and every new stack or client makes the next one cheaper to support. That's why nyxory uses a static cookbook instead of an LLM that re-thinks deployments at runtime, an open MCP surface instead of a proprietary protocol, and judgment over a fixed state machine. ## Independent by design We share what we generate. Your manifests and your application data — all exportable at any time. The deploy specs your agent builds are yours; you can take them off nyxory and run them somewhere else if you want. This isn't a marketing line. It's a structural choice. An execution layer is only worth trusting if it's neutral: it works with whichever agent and model you choose, and runs where you're allowed to run. It earns its place by operating well, not by holding your workloads hostage. --- Want to try it? **[Quickstart →](/docs/getting-started/quickstart)** Want to understand the architecture before you commit? **[How nyxory works →](/docs/concepts/how-nyxory-works)** --- # Builds & the execution surface Source: https://nyxory.com/docs/concepts/builds-and-the-execution-surface.md When your agent deploys on nyxory, its commands don't run on your laptop — and they don't run "in the cluster" with cluster credentials either. They run on a per-project **execution surface** we operate for you. This page explains that surface, because it's the part of the platform your agent touches most. ## Delegation, not credentials Conventional remote execution hands the caller a credential — an SSH key, a kubeconfig, a cloud token — and the security model degrades to "protect the credential." nyxory inverts that. Your agent holds exactly one thing: a `nyx_` token. It never sees a kubeconfig, never sees cloud credentials, never sees the cluster. A tool call expresses *intent* ("run this command in this project"); the platform authenticates the call, checks that you own the project, and only then performs the privileged act — inside your project's isolated environment and nowhere else. Every project is its own namespace with its own service account, network policies, and resource quota. This delegation model is the core of nyxory's architecture: a hybrid agent execution surface, where the agent expresses intent and the platform performs the privileged act. The architecture is patent pending. ## The workspace Each project has a persistent `/workspace` where the deploy work happens: - **`nyx_shell`** runs commands there — cloning your repo, inspecting `package.json`, running a `tsc --noEmit` before paying for a full build. - **`nyx_read_file` / `nyx_write_file` / `nyx_edit_file`** give your agent precise file access — reading configs, writing Kubernetes manifests. Your repo's source is **read-only to the platform**: writes under the cloned repo are blocked, so the agent can fix manifests and build artifacts but never silently rewrites code you authored. - **`nyx_set_secret`** stores secrets encrypted at write time. They're injected into your apps as env vars; the tool never shows a saved value again. Inside its own project the agent can read them, in no other project. ## Builds run off to the side `nyx_build_and_push_image` builds your container on our infrastructure — not on your machine, and not in your workspace. Each build runs in a single-purpose, isolated build environment with no access to other tenants, cluster internals, or platform credentials, then pushes to our registry and returns an `image_ref` your agent pastes into the Deployment manifest. Two builders are supported: - **Buildpacks (`cnb`, the default)** — zero config. The build detects your stack (Node, Python, Go, …) and produces an image without a Dockerfile. - **`dockerfile`** — used when your repo ships a real Dockerfile, with monorepo subpaths supported via a context argument. Tags are derived from your git SHA — no `latest`, fully reproducible rollbacks. ## Deploys are explicit Nothing deploys as a side effect. `nyx_deploy_manifests` applies exactly the manifests your agent wrote to your project — you can always ask your agent to show them first, and you can export them at any time. Rollout status, history, and logs come back through `nyx_app_get` (`view: deployments` for the history) and `nyx_app_logs`. ## Private repos just work Public repos clone straight into the workspace. Private GitHub repos go through the nyxory GitHub App: a one-time install in your browser, after which clones — including the clone inside an isolated build — use short-lived tokens minted per operation. No deploy keys, no PATs, nothing to rotate. See [Deploy from a private repo](/docs/guides/deploy-from-a-private-repo). ## Next steps - [How nyxory works](/docs/concepts/how-nyxory-works) — the brain call and the full deploy sequence - [Deploy a Next.js app](/docs/guides/deploy-a-nextjs-app) — the flow end to end - [Projects & accounts](/docs/concepts/projects-and-accounts) — how RAM/CPU ceilings shape what the agent can deploy --- # Dedicated instances Source: https://nyxory.com/docs/concepts/dedicated-instances.md A dedicated instance is a complete nyxory — console, operator, build runners, registry, optional AI gateway and run observability — running for one customer in one environment. Nothing is shared with other customers. Instances run today on STACKIT and AWS; Azure is being brought up; a bare-metal or on-premises data centre is a project we scope with you. ## What it needs - A Kubernetes cluster (managed or k3s) with a wildcard DNS entry and TLS for the instance domain. - A secrets manager of the cloud (the instance reads platform secrets through the External Secrets Operator; nothing is sealed into git). - Object storage for backups and exports. - A container registry per instance (`cr.`), seeded from nyxory's release registry. The bootstrap is infrastructure-as-code (OpenTofu) plus one Helm chart that renders every Argo application of the instance. Human decisions — domain, sizes, feature flags — live in one values file per instance. ## Who can access what Your teams use the console and the MCP exactly as on the shared platform. nyxory's operations access is administrative access to the instance from the EEA and Switzerland only, with multi-factor authentication, as set out in the [DPA](/dpa). Every MCP call lands in the instance's audit log, with the reason the agent gave for it. ## How upgrades land Every release image (console, operator, agent, build runners, gateway) is pinned per instance. An upgrade is a deliberate change of that pin in your instance's values, applied by Argo CD; the version is visible in git before it lands. ## Optional building blocks - **AI gateway**: a model egress with per-application budgets; apps call it with their pod identity, no key in the code. - **Argus**: observability for agent runs (the console's Argus page). - **Operations agent**: the agent that runs day-2 operations; available on dedicated instances. ## When you leave Manifests are exportable, volumes can be exported, and the DPA sets the return and deletion terms. The instance is yours to switch off. --- # How nyxory works Source: https://nyxory.com/docs/concepts/how-nyxory-works.md A deploy touches four places. Your coding agent starts it, a nyxory agent carries it off your machine, the nyxory cloud runs it, and operations keeps it healthy long after the first push. You only ever touch the first one — the rest is where nyxory does its work.
In your coding agent→In the nyxory agent→In the nyxory cloud→In operations
## In your coding agent You prompt — "deploy this repo." Your agent reasons about the stack and calls nyxory over MCP. The reasoning stays with your agent; nyxory never overrides it, and you never leave your chat. Which coding agent is your choice — Claude Code, Cursor, Codex, or any MCP client work the same way. [Connect your agent →](/docs/getting-started/connect-your-agent) ## In the nyxory agent Off your machine, a nyxory agent picks up the work: it reads the recipe for your stack, clones the repo into an isolated workspace, sets your secrets, builds a container image, and applies the deploy. This is the execution surface — the DevOps hours, done by an agent instead of your team, and never against your production by hand. The tool-by-tool detail lives in [MCP tools](/docs/reference/mcp-tools) and [Builds & the execution surface](/docs/concepts/builds-and-the-execution-surface). ## In the nyxory cloud Your app runs on European infrastructure, isolated per project — ingress, TLS, a public URL, configurable backups, all provisioned for you. You allocate the resources; nyxory runs what you allocate. How the account pool and project quotas relate is in [Projects & accounts](/docs/concepts/projects-and-accounts). ## In operations This is the part most platforms stop before. After it's live, the nyxory agent keeps it running — monitoring, patching and CVE response, change management, backups and restores, incident response — with every action on the record. Most of the real cost of software isn't the deploy; it's the months of operating it afterward, and that's the part nyxory owns continuously. [Day-2 operations →](/docs/guides/day-2-operations) --- Who drives which part — your own coding agent over MCP, or nyxory's operations agents — is your call, and you can mix them. See [Self-managed and operated](/docs/concepts/operating-models). --- # Self-managed and operated Source: https://nyxory.com/docs/concepts/operating-models.md nyxory is the operations layer your software runs on: its agents deploy it, keep it healthy, and re-ship it. You build it, nyxory runs it. How your software gets there is up to you — both paths share one cookbook and one set of primitives.
Self-managed

Your coding agent — Claude Code, Cursor, Codex, any MCP client — drives the deploy. You keep the reasoning.

Operated by nyxory

nyxory's operations agents run the production side — diagnosing, re-shipping, patching — after it's live.

## Self-managed — your coding agent, over MCP Your own coding agent — Claude Code, Cursor, Codex, or any MCP client — connects to nyxory and drives the deploy from your chat. You keep the reasoning; nyxory hands your agent the primitives and runs the result. This is the path every page in these docs describes, and it works today. - You pay tokens to your model vendor: the reasoning and the inference bill stay yours. nyxory provides the platform and runs what you ship. - Best when you already live in your coding agent and want it to handle deploys too. ## Operated by nyxory Beyond the deploy, nyxory's operations agents run the production side — the work that comes after "it's live": diagnosing, re-shipping, patching. This is the heart of the platform; see [Platform → Agents](/platform/agents) for the full picture. What your coding agent hands over, nyxory operates. This is the operator model for teams and regulated environments: production run on an SLA, with every action on the operations record, an audit trail IT can inspect. ## The deploy surface Either way, the work lands on a real target environment — the deploy surface. Your coding agent drives it over MCP; nyxory provisions and operates everything inside it, so you never touch the Kubernetes underneath:
Your coding agent
drives over MCP
Your target environment operated by nyxory
nyxory cluster · Kubernetes
AppAppApp
Cloud-native services
DatabaseBackupsMonitoring
Where that environment lives is your choice — from shared, the default, to your own cloud:
Shared nyxory cloudDefault
Isolated per project inside nyxory's sovereign European cloud. The default, included on Business (€480/mo).
Dedicated instance
Your own isolated instance in the nyxory cloud, no shared tenancy. Enterprise.
Bring your own cloud
nyxory deploys and operates inside your own cloud account. Enterprise.
Same cookbook, same primitives, same operations agent across all three — only the isolation and the underlying account change. Full detail on the [pricing page](/pricing). On a dedicated instance you can also decide how software gets built there: the templates your coding agents start from, the technologies your cloud strategy allows, and what the platform provides centrally. That is an Enterprise feature, and nyxory switches it on for you. See [Architecture requirements](/docs/guides/architecture-requirements). ## Same cookbook either way Both paths retrieve recipes from the same source and call the same primitives. The cookbook is the moat — not which agent drives it. Next: [How nyxory works →](/docs/concepts/how-nyxory-works) --- # Projects & accounts Source: https://nyxory.com/docs/concepts/projects-and-accounts.md Your **account** is the top-level container: it owns billing, members, and the resource pool. **Projects** live inside your account; each project is an isolated environment where your apps run. Most users start with one or two projects (e.g. `staging`, `prod`) and grow from there. Projects belong to a **workspace**: your personal one, or a shared workspace whose owner adds members with the role admin or member. Projects in a shared workspace run on the workspace owner's plan. Your agent sees every workspace it can act in, and the projects in it, through `nyx_project_list`. ## The RAM pool Each project draws RAM from your account **pool**: your plan's baseline plus any RAM packs you've booked. Storage comes from a separate pool (your plan's storage plus any storage packs), not from RAM. If your pool is 8 GB and you've assigned 5 GB to `prod` and 2 GB to `staging`, 1 GB is left. Raising `staging` to 4 GB needs either less for `prod` or another RAM pack. Your agent handles the resize; booking a pack is a person's step in the console. The calls, and which step changes the bill, are in [Scaling and RAM](/docs/guides/scaling-and-ram). ## Isolation between projects Projects are sealed off from each other, also inside the same workspace. Where a resource has its own login, each project (or each bucket) gets its own identity, and the system that holds the resource checks it: the separation is not a filter in front of a shared account.
Inside a project, apps reach each other privately. Between projects, only the public endpoint is reachable, the same way it is for anyone on the internet.
| Resource | What keeps other projects out | |---|---| | **Apps and databases you run** | Each project has its own network boundary. Apps in a project reach each other; traffic from other projects is blocked. A database you run in one project is not reachable from another. | | **Your agent's access** | The tools that act inside a project run with a role bound to that project alone. | | **Buckets** (where object storage is available) | Every `Bucket` gets its own credentials at the storage provider, and a bucket policy there refuses every other key, including those of other projects. See [Storage and backups](/docs/guides/storage-and-backups#object-storage). | | **Git on a connected Gerrit** | Every project reads with its own read-only account, and only the repositories the repository owner granted to that project. See [Deploy from a private repo](/docs/guides/deploy-from-a-private-repo#gerrit-one-read-account-per-project). | | **Secrets** | Project and app secrets live in their project. Its workloads and its agent can read them; no other project can. | ## Console In the console, a project's RAM sits on its **Apps & agents** page, next to the apps that use it. From the CLI: `nyx account ram` and `nyx project state`. Next: [The cookbook →](/docs/concepts/the-cookbook) --- # The cookbook Source: https://nyxory.com/docs/concepts/the-cookbook.md The cookbook is a set of markdown recipes your agent retrieves on demand. Recipes are written by us — humans, working from real deploys — and applied with your agent's judgment. ## What's inside One bundle, organized by topic: the standard deploy flow, a verify checklist, debug recipes, quota walls and how to negotiate them, day-2 operations, and multi-app / multi-service patterns. Stack-specific gotchas — a Next.js prerender quirk, an Astro preview-host allowlist, sizing a FastAPI + Celery pair — live inside those sections, so your agent doesn't relearn them per deploy. Your agent gets the cookbook in one `nyx_brain` call — the evergreen core plus the stack and topic recipes retrieval judges most relevant to your repo and briefing — alongside your project's current state. There's no follow-up retrieval step on the agent's side; the matching happens server-side before the response. With architecture requirements, an Enterprise feature on dedicated instances, your organisation's own rules come first: your reference architectures and your cloud strategy win over every recipe. See [Architecture requirements](/docs/guides/architecture-requirements). ## Why static, not generated We don't ask an LLM to write the recipe at runtime. Three reasons: - **Predictability.** A recipe that worked yesterday works today. No silent drift between deploys. - **Debuggability.** When something goes wrong, we can read the exact text the agent saw and reason about why. - **Auditable, independently released.** A recipe is fixed text, not a fresh generation, so we can pin exactly which version served a deploy — and update recipes on their own cadence, decoupled from the backend, with no redeploy and no agent rebuild on your side. ## Judgment over orchestration The recipe is a suggestion shaped by experience, not a fixed sequence. When your agent sees something the recipe didn't anticipate — a non-standard build config, a missing secret, a registry the recipe doesn't know — it deviates. We never force a state machine. That's the trade-off: outputs aren't byte-identical across runs, but they're *outcome-equivalent*. Two deploys of the same repo by the same agent both end with App Available, Ingress reachable, docs present. ## How to read recipes Recipes are agent-facing — written in the imperative second person, addressed to the agent reading them. You don't browse them on this site. If you want to see what your agent saw on a particular deploy, ask the agent — the cookbook is the `nyx_brain` tool result, and most clients let you inspect MCP tool results. Next: [Deploy a Next.js app →](/docs/guides/deploy-a-nextjs-app) --- # Connect your agent Source: https://nyxory.com/docs/getting-started/connect-your-agent.md MCP (Model Context Protocol) is the contract layer between your coding agent and nyxory. Any MCP-speaking client can plug in. There is one endpoint and one auth mechanism, and each client needs one small step to register it. - **Endpoint:** `https://api.nyxory.com/mcp` (Streamable HTTP) - **Auth:** OAuth on first connect — the client opens a browser and your human approves. No token to generate or paste for interactive use. > **Note:** New accounts are activated by the nyxory team. Until yours is, every tool call returns `approval_pending` ("your account is awaiting approval"). Nothing to fix on your side; the same setup works as soon as the account is approved. Every MCP-speaking coding agent works. Jump to yours:
Claude Codenyx claude install Cursornyx cursor install Codexnyx codex install VS Codenyx vscode install Claude Desktopvia claude.ai Any MCP clientHTTP endpoint
## The fastest path: `nyx setup` One command installs the `nyx` CLI, signs your human in, detects the MCP-capable clients on the machine (Claude Code, Cursor, Codex, VS Code, Claude Desktop), and registers nyxory with each one. ```bash curl -fsSL https://nyxory.com/install.sh | bash # macOS / Linux / WSL irm https://nyxory.com/install.ps1 | iex # Windows PowerShell ``` The installer runs `nyx setup` for you. To re-run it later — it's idempotent and leaves your other MCP servers untouched: ```bash nyx setup # pick the clients to wire, interactively nyx setup --all # wire every detected client, no prompts ``` ## Wire a specific client If you only use one editor, register nyxory there directly. Each command below writes the client's own config at its own path — you never hand-edit a config file. ### Claude Code ```bash nyx claude install ``` This calls Claude Code's own CLI (`claude mcp add`) to register nyxory as a remote HTTP endpoint. To do it without `nyx`: ```bash claude mcp add --transport http --scope user nyxory https://api.nyxory.com/mcp ``` ### Cursor ```bash nyx cursor install ``` Writes the nyxory server into `~/.cursor/mcp.json` (or `./.cursor/mcp.json` with `--scope local`), merging alongside any servers already there. ### Codex ```bash nyx codex install ``` Adds an `[mcp_servers.nyxory]` block to `~/.codex/config.toml`, then runs `codex mcp login nyxory` to complete OAuth — Codex won't prompt for it on its own, so this step is required. ### VS Code ```bash nyx vscode install ``` Writes an `http`-transport entry into VS Code's user `mcp.json` (`~/Library/Application Support/Code/User/mcp.json` on macOS, `%APPDATA%\Code\User\mcp.json` on Windows, `~/.config/Code/User/mcp.json` on Linux). ### Claude Desktop Claude Desktop connects through your claude.ai account, not a local file. Run `nyx setup` and it opens the connectors page — or add a custom connector pointing at `https://api.nyxory.com/mcp` yourself. ### Any other MCP client nyxory speaks standard MCP over HTTP. Point your client at the endpoint: ```json { "mcpServers": { "nyxory": { "url": "https://api.nyxory.com/mcp" } } } ``` A `tools/list` call returns the authoritative surface. The tools are catalogued in the [MCP tools reference](/docs/reference/mcp-tools); the workspace and build primitives are described in [Builds & the execution surface](/docs/concepts/builds-and-the-execution-surface). ## Authentication Interactive setups need no token: every client runs its own OAuth handshake against the endpoint the first time it connects, and your human approves in the browser. For **headless or CI** use, mint a long-lived token on a signed-in machine and send it as a bearer: ```bash nyx token create my-ci-runner # → prints the plaintext ONCE — store it as a secret ``` Rotate with `nyx token delete ` followed by another `create`. See the [CLI reference](/docs/reference/cli) for the full `nyx token` surface. ## Verify it's wired Ask your agent to call `nyx_project_list`. It returns your account, workspaces, and projects, which confirms the OAuth round-trip worked. The full tool list is in the [MCP tools reference](/docs/reference/mcp-tools). Next: run the [Quickstart](/docs/getting-started/quickstart). Deploying private GitHub repos? That's a one-time GitHub App install — see [Deploy from a private repo](/docs/guides/deploy-from-a-private-repo). > **Caution:** If it doesn't connect, three things go wrong most often. **Wrong URL** — it's `api.nyxory.com/mcp`, not `api.nyxory.app` (that's where deployed apps live). **OAuth not completed** — for Codex, make sure `codex mcp login nyxory` finished in the browser; for the others, reopen the client so it re-triggers the approval. **MCP transport disabled** — check that MCP is enabled in your client's settings. --- # How to use these docs Source: https://nyxory.com/docs/getting-started/how-to-use-these-docs.md These docs cover one thing, end to end: how your coding agent ships software to production on nyxory and keeps it running. There are two ways to find what you need — **ask Nova**, or move through the **five sections**. Here's the fastest path to each. ## Ask Nova — the shortcut Every page has a chat button in the bottom-right: **Nova**, nyxory's guide. Ask in plain language — Nova answers straight from these pages and links you to the exact one, so you never have to leave to find an answer.
Nova · nyxory's guide
How do I put my app on my own domain?
Add it with nyx domain add, then point a CNAME at nyxory and it verifies automatically. Full steps: Add a custom domain →
Each question opens a **fresh conversation**, so a new ask never gets tangled in an old thread — and past ones are one click away under **History**. On a wide screen, dock Nova to the side and read the docs right next to it. > **Nova only answers from these docs.** If something isn't covered yet, it says so plainly rather than guessing — and you can leave a note for the team. An honest "not documented yet" beats a confident wrong answer. ## The five sections The sidebar groups every page into five sections. Here's what lives where:
Getting Started

Connect your coding agent and ship your first repo — five minutes end to end.

Concepts

The mental model — what nyxory is and how it takes your software live and runs it.

Guides

Step-by-step recipes for real tasks — deploy, scale, back up, operate day two.

Reference

The exact surface — every CLI command, every MCP tool, and what each plan includes.

Background

The why behind the product — the shift nyxory is built for.

## Not sure where to start? - **New to nyxory?** Read [What is nyxory?](/docs/getting-started/what-is-nyxory), then run the [Quickstart](/docs/getting-started/quickstart). - **Know it already, want to ship?** Go straight to the [Quickstart](/docs/getting-started/quickstart) — connect once, then deploy from a prompt. - **Looking something up?** Jump to the [CLI reference](/docs/reference/cli) or the [MCP tools](/docs/reference/mcp-tools). Or just ask Nova. That's what it's there for. --- # Quickstart Source: https://nyxory.com/docs/getting-started/quickstart.md Two parts: **connect once**, then **deploy from your chat**. The first part sets up the `nyx` CLI and wires your coding agent to nyxory; after that, deploying is a prompt. Five minutes end to end for a standard repo. > **Stuck on any step?** Ask **Nova** — the chat button at the bottom-right of every docs page. It answers straight from these docs and points you to the exact page. You never have to leave to find an answer. ## 1. Connect **One command** installs the `nyx` CLI, signs you in, and wires every AI client it detects on your machine: ```bash curl -fsSL https://nyxory.com/install.sh | bash ``` On Windows use `irm https://nyxory.com/install.ps1 | iex`; with Homebrew, `brew install nyxory/tap/nyx && nyx setup`. **Or wire one client directly** with `nyx claude install`, `nyx cursor install`, `nyx codex install`, or `nyx vscode install`. Authentication is OAuth on first connect; there's no token to paste. Claude Desktop, custom MCP clients, and troubleshooting are in [Connect your agent](/docs/getting-started/connect-your-agent). **Any other MCP client?** Point it straight at the nyxory endpoint: ``` https://api.nyxory.com/mcp ``` > **Prereqs:** a coding agent that speaks MCP (Claude Code, Cursor, Codex, VS Code, or any MCP client) and a git repo you want to deploy — any stack (Next.js, Astro, FastAPI, a Compose monorepo). ## 2. Open the repo in your agent Open the repo in the same workspace as your connected client. Anything you'd ship to staging is fair game. Private GitHub repo? Your agent hands you a one-time GitHub App install link mid-deploy — see [Deploy from a private repo](/docs/guides/deploy-from-a-private-repo). ## 3. Prompt Say: > deploy this repo to nyxory Your agent calls `nyx_brain`, gets back the cookbook recipe for your stack plus your project's current state, and follows it — cloning the repo into your project workspace, setting secrets, building and pushing the image, deploying the manifests. ## 4. Watch it land Your agent reports progress as tool calls. When the deploy resolves, it returns a URL like `https://yourapp.nyxory.app` — and the app shows up in the console, live and operated:
my-nextjs • Available
https://my-nextjs-a1b2c3.nyxory.app ↗
1 pod Memory 210 MiB / 512 MiB CPU 12m / 250m Requests 24h 5,639 Errors 0.1%
## 5. Verify ```bash curl -I https://yourapp.nyxory.app ``` Expect a `200 OK`, or just open it in your browser. Done. From here: - **[Connect another client →](/docs/getting-started/connect-your-agent)** — Claude Desktop, Codex, or custom MCP setups - **[How nyxory works →](/docs/concepts/how-nyxory-works)** — the mental model behind those tool calls - **[Deploy from a private repo →](/docs/guides/deploy-from-a-private-repo)** — one-time GitHub App install - **[Add a custom domain →](/docs/guides/add-a-custom-domain)** — bind your own hostname > **Environments:** Production is MCP at `api.nyxory.com/mcp`, apps at `*.nyxory.app`, console at `console.nyxory.com`. --- # What is nyxory? Source: https://nyxory.com/docs/getting-started/what-is-nyxory.md nyxory is where your AI coding agent ships to production: the independent execution layer for AI-built software. Your agent writes the software; a **nyxory agent** takes it onto European cloud infrastructure and keeps it running there: deployed, secured, operated, every action on the record. You stay in your coding agent the whole time; the last mile runs itself.
Your coding agent
Claude Code, Cursor, Codex — writes the software
nyxory agent
takes it live and keeps it running
Cloud infrastructure
European, isolated per project
The nyxory agent owns the last mile, from "it builds on my machine" to "it runs in production, safely":
Deploy
Every push shipped to a live URL in minutes: build, image, manifests, ingress, TLS.
Secure
Secrets, isolation per project, patching and CVE response, on European infrastructure.
Operate
Monitoring, scaling, backups, and incident response after it's live, every action on the record.
Your code stays in your own Git, and the operations record is a full audit trail, so control stays with the people accountable for production. ## What nyxory is *not* - **Not a deploy state machine.** The nyxory agent works from recipes shaped by experience, not a fixed sequence — and it never overrides your coding agent's reasoning. - **Not an LLM that re-thinks what your agent already does well.** Recipes are static, hand-written, and authored by us; nothing is generated at runtime. - **Not lock-in.** Your manifests and your data are exportable at any time. Saved secret values are not shown again, so keep your own copy. ## How it connects Your coding agent reaches nyxory over MCP, and the nyxory agent does the work from there. The tool-by-tool mechanics — the entry point, the primitives, a typical deploy — live in [How nyxory works](/docs/concepts/how-nyxory-works). When you're ready to ship one, the [Quickstart](/docs/getting-started/quickstart) takes you from install to a live URL. --- # Add a custom domain Source: https://nyxory.com/docs/guides/add-a-custom-domain.md Bind your own domain to a deployed app. The TLS cert is issued and renewed for you; you only touch DNS. > **Prereqs** > - A deployed app (see [Deploy a Next.js app](/docs/guides/deploy-a-nextjs-app) for the first deploy) > - A domain you control with registrar / DNS access > - Either the console or a connected agent — both paths work 1. **Pick a hostname.** Apex (`example.com`) or subdomain (`app.example.com`) — both work, and both use record types every registrar supports. 2. **Bind the domain to your app.** ### Console **Project → Settings → Domains → Add domain.** Pick the app, paste the hostname, click Add. The page shows the DNS target you need to point at next. ### Via your agent ``` add example.com to my widget app on nyxory ``` Your agent resolves your project (via `nyx_project_list` / `nyx_app_list`), calls `nyx_domain` with `action: add`, the hostname, app, and project, and reports back the DNS target. ### CLI ```bash nyx domain add example.com --app widget ``` 3. **Point your DNS at the returned target.** The response gives you the exact target to use. - **Subdomain:** add a CNAME from your hostname to the target the platform publishes. - **Apex (`example.com`):** add an A record pointing at the IP the response returns. Every registrar supports A records — no ALIAS/ANAME workaround needed. 4. **Wait for the cert.** ```bash nyx domain status example.com --watch ``` Or refresh the project's **Domains** settings. Typical first issuance: **2–5 minutes**. The cert auto-renews thereafter — you don't touch it again. 5. **Verify.** ```bash curl -I https://example.com ``` Expect `200 OK` and a valid Let's Encrypt cert. ## Listing + removing ```bash nyx domain list # all your bound domains nyx domain list --app widget # just one app nyx domain remove example.com # detach: removes the route and the certificate ``` ## Troubleshooting > **Caution:** > - **DNS not propagated.** Run `dig example.com` and check it resolves to the target the response gave you. If it doesn't show up yet, your registrar hasn't propagated — wait 60 seconds and re-check. > - **CAA records blocking the cert.** If you have a `CAA` record at the apex that doesn't include `letsencrypt.org`, the issuance fails silently. Either remove the CAA or add a `0 issue "letsencrypt.org"` entry. > - **`CertPending` for more than 10 minutes.** Something's wrong upstream. Open the console's domain detail — it surfaces the latest provisioning event. If you're stuck, `nyx domain remove` + re-add usually clears it. --- # Architecture requirements Source: https://nyxory.com/docs/guides/architecture-requirements.md > **An Enterprise feature**, available on dedicated instances, where nyxory switches it on for you. Not on the shared platform. Your organisation already knows how software should be built: which templates teams start from, which technologies the cloud strategy allows, what the platform provides centrally. On a dedicated instance you write that down once. Every coding agent learns it from `nyx_brain` before it writes code, the platform refuses a rollout that breaks it, and a team that needs to deviate requests an exception that a person decides. A workspace without requirements behaves exactly as before. ## The Architecture page In the console, open **Settings › Architecture**. The page has five sections, in this order: | Section | What it decides | Who changes it | |---|---|---| | **Reference architectures** | Templates the agents build from | architecture owners | | **Cloud strategy** | Which technologies are allowed | architecture owners; workspace owners and admins can make it stricter for their workspace | | **Platform building blocks** | What the platform provides and what teams should not build themselves | workspace owners and admins | | **Exceptions** | Who may deviate and for how long | architecture owners decide | | **Architecture reviews** | What the agents asked and which template they got | read-only | **Architecture owners** are a small group of people per instance, typically your architecture or platform team. nyxory assigns the role on your instance. Members and agents read everything they need to build. Only people change requirements and decide exceptions, never an agent. ### Reference architectures A reference architecture is a template for one kind of software: what it is for, which platform building blocks it uses, and build instructions the agent follows. The page shows them as a gallery, each with its architecture diagram. - **From nyxory** are the templates nyxory maintains, such as a web app with Postgres or an agent with the AI gateway. A template that does not fit your cloud strategy shows greyed out with the reason and is not offered to the agents. - **Own** are yours and apply to all workspaces on the instance. They are offered ahead of nyxory's. **Create reference architecture** opens an editor with a live preview. A template is Markdown with a YAML header: ```yaml --- id: web-service-postgres title: Web service with Postgres purpose: Web service on the platform's Postgres database. signals: [web service, node, api, postgres, database] components: [postgres, public_url] diagram: nodes: - {id: web, kind: ingress, label: "Public URL"} - {id: app, kind: app, label: "Web service"} - {id: db, kind: postgres, label: "Postgres"} edges: [[web, app], [app, db]] --- ## Build instructions … ``` `id`, `title`, `purpose`, `signals` and either `diagram` or `image` are required. `signals` are the keywords that match a plan to the template. A technology the template needs beyond the platform building blocks goes under `technologies`, each with a `reason`. The console checks it against your cloud strategy and warns when saving, and the review then names the conflict. In the build instructions, the console fills in `__APP__`, `__NAMESPACE__`, `__REGISTRY__` and `__GATEWAY__`. It increments `version` on every save. Projects built from an older version show "newer version available", and nothing is rebuilt for them. ### Cloud strategy Paste your organisation's cloud strategy with **Insert strategy**. An architecture owner chooses under **Where should the strategy apply?**: - **For the whole instance** applies it to all workspaces in this instance. - **Only for this workspace** applies it here in addition. This workspace becomes stricter, all others stay as they are. Workspace owners and admins without the role get **Make it stricter for this workspace** for the second case. A workspace can add to the instance-wide strategy, never loosen it. The AI model connected to your instance reads it section by section and turns it into proposals, each with the sentence from the document and where it stands. A proposal whose sentence is not in the document word for word is discarded. Nothing applies until you **Adopt** a proposal, one by one or with **Adopt all**. A requirement takes one of two forms: - **Databases: only PostgreSQL** allows one or more technologies in a category and rules out the rest of it. - **Kafka: not allowed** rules out one technology. Each requirement shows where the platform detects it: in the code, in the container image, in the bill of materials. A technology the platform does not know still reaches the agent, and the page marks it "unknown to the platform: the agent is told, it is not enforced". A new version of the document comes in through **Insert new version** and shows its proposals as the difference to the current one. Only people who may change the strategy see the full text. Everyone else, agents included, sees the requirements with their sentence. ### Platform building blocks For each building block a workspace answers **allowed** or **no**. A **no** needs a **Reason**, and you can add a **Note for the agent on what to use instead**, for example the central database and the secret its credentials are in. Both reach the agent word for word. | In the console | `subject` | Checked when | |---|---|---| | Database from the platform | `postgres` | a Postgres database is created | | File storage from the platform | `bucket` | a bucket is created | | Keep data inside the container | `storage` | a container gets its own disk space, such as a self-run database | | Address on the internet | `public_url` | the platform creates the public address of a new app | | Custom domain | `custom_domain` | a custom domain is added | | Software from outside sources | `images` | an image comes from a source not on your list. The platform's own registry is always allowed. | | Memory above a limit | `memory` | a container's memory limit is set above the limit | Below the building blocks, **Still running although no longer allowed** lists what was there before a requirement and keeps running. It stays untouched. The list includes running containers whose image falls under a technology requirement of the cloud strategy, such as a `mysql:8` container after "Databases: only PostgreSQL". For each of them, **Request exception** leads to the project's exception form, in case it should keep running. ## What your coding agent gets The agent calls `nyx_brain` with the project and describes its plan in `agent_briefing`: what it builds, its components, its data stores. On top of the cookbook, the answer carries: | Field | What it holds | |---|---| | `data.reference_architectures` | Up to three templates that fit the plan, each with why it fits and whether it is yours or nyxory's. Empty when none fits. | | `data.ranking` | `model` when the AI model connected to your instance ranked them, `keyword` when they were matched by keywords alone, for example with no model connected. | | `data.cloud_strategy` | The technology requirements that matter for this repo, each with its sentence from the strategy. Next to them is a check of the repo: per file and line, what was found and whether it is allowed, what to rebuild it on, or an exception until a date. Missing when no requirement applies. | | `data.requirements` | The platform building blocks the workspace rules out, each with its reason and note. Missing when none is set. | The agent picks a template and calls `nyx_brain` again with `reference` set to its `id`. The answer is the build instructions with the project's values filled in. When the agent then rolls out from the same session, the project counts as built from that template, and the template's page lists it. Your requirements win over every cookbook recipe and every reference architecture. The repo check reads dependencies, Dockerfile base images and services in a compose file. What it could not read, it says so, and the agent checks that part itself. ## What happens at rollout The platform checks every new rollout against the requirements, on every path into the project: `nyx_deploy_manifests`, a push with a `deploy/` folder, and `kubectl` through `nyx_shell`. A rollout that breaks a requirement is refused before anything is applied. The message starts with a code the agent can read, shown wrapped here: ``` requirement:denied:technology:mysql: image "mysql:8" (mysql) is not allowed in workspace "Orders". … ``` The code is `requirement:denied:`, and for a technology `requirement:denied:technology:`. The rest of the message carries the reason, the alternative, the note for the agent where you set one, and how to request an exception. On some paths the code follows a prefix, so the agent looks for `requirement:` anywhere in the message. A refused `deploy/` push leaves the running version serving. **Running workloads stay untouched.** Requirements apply to what is created or changed. An update is checked only for images that are new in it, and lowering a memory limit always works. ## Request an exception When a project needs something a requirement rules out, the agent requests an exception with `nyx_exception_request`. A member does the same on the project, under **Settings › Architecture** with **Request exception**. | Parameter | Value | |---|---| | `project` | the project | | `subject` | `technology:` for a cloud strategy requirement, such as `technology:mysql`, or a building block from the table above, such as `storage` | | `reason` | why the project needs it and how it will be replaced | | `duration` | `30`, `90` or `365` days, or `unlimited`. Default `90`. | The answer is the request with its state, and `created` says whether it is new. Asking again for the same thing returns the open request, or the exception that already applies, instead of a second one. A project has at most ten open requests. **A person decides, never an agent.** An architecture owner sees the request under **Exceptions**, with its reason and who requested it, and chooses **Approve** or **Reject**. Rejecting needs a reason, so the team knows what to do instead. The person deciding can pick a different duration from the same choice. An approved exception applies after about a minute, in the rollout check and in the next `nyx_brain` answer. The agent tells you that the request waits for a decision and plans with the alternative until then. An exception moves through these states: | State | Meaning | |---|---| | `requested` | waits for a decision | | `approved` | applies, until its end date or without one | | `rejected` | decided against, with a reason | | `withdrawn` | the requester took it back | | `revoked` | an approved exception was ended early | | `expired` | the end date passed | | `no_longer_needed` | the requirement was lifted while the request was open | Fourteen days before an exception ends, the project's feed and alert channels say so. When it expires or is revoked, what runs stays in place, and a new rollout of that technology is refused again. An `unlimited` exception never expires. ## Example: from plan to approved exception A team builds an order service. Your cloud strategy says "Databases: only PostgreSQL", and the team also ships a reporting tool that only runs on MySQL.
  1. Agentnyx_brain(agent_briefing: "order service in Node.js, orders in a database, ships a reporting tool")
    data.reference_architectures puts your template web-service-postgres first. data.cloud_strategy holds "Databases: only PostgreSQL" and flags mysql2 in package.json as not allowed, to be rebuilt on the platform's Postgres database.
  2. Agentnyx_brain(reference: "web-service-postgres")
    The build instructions come back with the project's values filled in. The agent moves the order service onto Postgres.
  3. Agentnyx_deploy_manifests(…) with the reporting tool's mysql:8 container
    Refused with requirement:denied:technology:mysql. Nothing is applied.
  4. Agentnyx_exception_request(subject: "technology:mysql", reason: "reporting tool runs only on MySQL, replaced next quarter", duration: "90")
    The request is requested with created: true. The agent tells you that a decision is pending.
  5. Architecture ownerApprove under Exceptions
    The exception applies about a minute later, for 90 days.
  6. Agentnyx_deploy_manifests(…) again
    The container goes through. The next nyx_brain answer shows the exception with its end date.
Related: [MCP tools](/docs/reference/mcp-tools) · [Configure your app from the repo](/docs/guides/configure-from-the-repo) · [The cookbook](/docs/concepts/the-cookbook) --- # Deploy on push Source: https://nyxory.com/docs/guides/auto-deploy.md Turn on **auto-deploy** and every push to the watched branch rebuilds the app from the new commit and rolls it out, with each deploy on the record. No pipeline to write, no runner to keep alive, no deploy key to rotate. ## Turn it on Auto-deploy is set per app, in the console (there is no CLI flag or MCP tool for it): 1. **Connect the repo once.** For GitHub, that's the [nyxory GitHub App](/docs/guides/deploy-from-a-private-repo#github). For other Git hosts, an [HTTPS Git connection](/docs/guides/deploy-from-a-private-repo#other-git-hosts-over-https) or, on a connected Gerrit, the [project's read account](/docs/guides/deploy-from-a-private-repo#gerrit-one-read-account-per-project). 2. **Deploy the app once from that repo.** The console captures the app's blueprint from that deploy; the **Auto-deploy** panel on the app appears after it. 3. **Switch Redeploy on push on.** 4. **Pick the branch to watch**: `main`, a `staging` branch, whatever maps to that environment. Left blank, nyxory watches `main`, not your repository's default branch, so set it explicitly if yours is `master` or anything else. That's the whole setup. ## What happens on a push
A bad push never takes the running app down. Fix it and push again; the next commit goes through the same path.
On GitHub, the push notifies nyxory right away; repos on other hosts are checked about once a minute. You follow each deploy in the console, where the panel shows building, deploying, deployed, or action required, or from your agent with `nyx_build_status`. On a dedicated instance, a `deploy/` folder in the repo is applied on the same push. The manifests in it, a Postgres database included and a bucket where the instance has object storage, become the app's configuration, and the console shows the commit it came from. A folder that breaks a rule is refused before anything is written, and the running version keeps serving. See [Configure your app from the repo](/docs/guides/configure-from-the-repo). ## Good to know - **CronJobs are included.** A push rolls the new image into an app's CronJobs, and the next scheduled run uses it. See [Jobs and CronJobs](/docs/guides/jobs-and-cronjobs). - **Restores switch it off.** An `app` or `full` restore turns auto-deploy off so a push can't race the rollback. It stays off until you switch **Redeploy on push** back on. - **One branch, one environment.** Point a production app at `main` and a staging app at `staging`; each app watches its own branch, so the right commit always lands in the right place. Related: [Configure your app from the repo](/docs/guides/configure-from-the-repo) · [Deploy from a private repo](/docs/guides/deploy-from-a-private-repo) · [Day-2 operations](/docs/guides/day-2-operations) --- # Configure your app from the repo Source: https://nyxory.com/docs/guides/configure-from-the-repo.md > **Currently available on selected dedicated instances.** Coming to the shared platform next. Your app's configuration can live in the repo, next to its code. Put the manifests in a `deploy/` folder at the repository root, and every push to the branch the app watches applies them. Replicas, environment, a Postgres database and an object storage bucket are then versioned with the code and reviewed like code, and the console shows which commit the running configuration came from. ## The `deploy/` folder nyxory reads the `*.yaml` and `*.yml` files at the top level of `deploy/`. Without the folder nothing changes, and the platform keeps generating the app's configuration as before. Other folders such as `k8s/`, `manifests/` or charts are not read on push, so move the manifests you want to own into `deploy/`. `deploy/` is always read at the repository root, also when an app builds from a subfolder. In a monorepo every app therefore reads the same folder, and in one project a push of a second app from that repository is refused, because the objects it names already belong to the first app. | Kind | What the platform does | |---|---| | `Deployment` | applies it | | `Service` | applies it, `ClusterIP` only and with a selector | | `ConfigMap` | applies it | | `Ingress` | maps each rule onto the app's own domain, so TLS and protection of the public address stay with the platform | | `Postgres` | provisions a database for the project and keeps it | | `Bucket` | provisions a bucket for the project and keeps it, on instances with object storage | `Postgres` and `Bucket` use `apiVersion: nyxory.com/v1alpha1`, the others their usual `apps/v1`, `v1` and `networking.k8s.io/v1`. The app container runs the image nyxory built from the pushed commit. Write `image: IMAGE_REF` where that image belongs; other images, a `redis:7` sidecar for example, stay as written. Without an `IMAGE_REF`, the first container of the first Deployment gets the built image. Namespace, platform labels and ownership are set by the platform, so leave them out. ```yaml # deploy/app.yaml apiVersion: apps/v1 kind: Deployment metadata: name: web spec: replicas: 2 selector: matchLabels: {app: web} template: metadata: labels: {app: web} spec: containers: - name: web image: IMAGE_REF ports: [{containerPort: 8080}] env: - {name: GREETING, value: "hello"} --- apiVersion: v1 kind: Service metadata: name: web spec: selector: {app: web} ports: [{name: http, port: 80, targetPort: 8080}] ``` Keep the names the first deploy created, usually the app's name. A new name creates a second Deployment next to the first one. ### Start from the generated configuration The app page in the console shows under **Configuration** the manifests the app runs with right now, read from the cluster, one object at a time. **Copy** puts the selected object on the clipboard, and you paste it into a file in `deploy/` as a starting point. Runtime fields are already stripped and the names are the ones the first deploy created. Before you push, set `image: IMAGE_REF`, remove `metadata.namespace` and every label or annotation under `nyxory.com`, and leave out kinds the table above does not list. Values with key-like names come out masked and Secrets are not shown. Store those values with `nyx_set_secret` and reference the Secret by name. ### What happens on a push Push to the watched branch and nyxory builds the image from the new commit, as with any [deploy on push](/docs/guides/auto-deploy). Then it checks every object in `deploy/`, runs a dry run of all of them, and only when everything passes does it apply the folder and roll out the new image. The app page in the console shows the result under **Configuration** as "Source: from your repo, deploy/ @ <commit>". Nothing is pruned. An object the generated configuration had and `deploy/` does not name stays in place, and so does every field `deploy/` never sets. ### A refused push leaves the app running When one object breaks a rule, nyxory refuses the whole push before anything is written, and the running version keeps serving. The app page says so under Configuration, with the file and the reason: ``` Last push rejected, nothing applied, the running version stays: deploy/postgres.yaml: Postgres orders, tier dedicated is not available yet; use tier: shared ``` Fix the file and push again. These are always refused: - a `Secret`, since secret values never come from the repository (your coding agent stores them with `nyx_set_secret`, and `deploy/` references them by name) - any kind not in the table above, RBAC and cluster-wide objects included - a `metadata.namespace` other than the project's, and labels or annotations under `nyxory.com` - `traefik.*` and platform-owned annotations on an Ingress, and an Ingress host that is not one of the app's addresses (add the domain first) - host namespaces, `hostPath` volumes, privileged containers, and a `serviceAccountName` other than the app's own - a Service of type `LoadBalancer` or `NodePort`, `externalIPs`, and names reserved for the platform (`nyx-*`, `nyxory-*`) - a symlinked `deploy/` folder or file The folder holds about 10 KB of YAML. A larger one fails the build with a message saying so. ## Your coding agent With the nyxory MCP connected, your coding agent calls `nyx_config_reference` before it writes `deploy/`. The answer lists the allowed kinds, the fields of `Postgres` and `Bucket` with type, default and description as installed on your instance, the rules a push is checked against, and an example per kind. The whole documentation is also one file at [nyxory.com/llms-full.txt](https://nyxory.com/llms-full.txt). The platform does not commit to your repository. Its agent works on a read-only clone. When a fix needs a change to `deploy/` or to other files you wrote, it shows the change, and you or your coding agent commit and push it. ## A Postgres database: `deploy/postgres.yaml` Declare the database next to the app and nyxory creates it on the platform's database server, with two roles and two Secrets in your project. Nobody writes a password anywhere. ```yaml # deploy/postgres.yaml apiVersion: nyxory.com/v1alpha1 kind: Postgres metadata: name: orders spec: tier: shared ``` | Field | Values | |---|---| | `tier` | required, and `shared` is the only value from `deploy/` | | `secretName` | optional, defaults to `-postgres`, fixed after the first push | | `auth` | `password` (default) or `certificate`, see [below](#postgres-with-a-client-certificate) | | `deletionPolicy` | ignored, data from the repo is always kept | Any other field, and any label or annotation under `nyxory.com`, refuses the push. **The two Secrets.** `orders-postgres` is for the running app. Its role reads and writes rows and cannot change the schema. `orders-postgres-migrate` is for the migration and owns the schema. Both carry the same keys: | Key | Holds | |---|---| | `DATABASE_URL` | the full connection string, with `sslmode=verify-full` | | `PGHOST`, `PGPORT`, `PGDATABASE`, `PGUSER`, `PGPASSWORD` | the same values one by one, for tools that read no URL | | `PGSSLMODE`, `PGSSLROOTCERT` | `verify-full` and `/etc/nyxory-postgres/ca.crt` | | `ca.crt` | the database server's CA certificate | | `PGHOST_RO` | a read-only replica host, only when the server runs more than one instance | The Deployment reads the Secret with `envFrom` and mounts it, so the client finds the CA the connection string verifies against: ```yaml spec: containers: - name: web image: IMAGE_REF envFrom: - secretRef: {name: orders-postgres} volumeMounts: - name: pgca mountPath: /etc/nyxory-postgres readOnly: true volumes: - name: pgca secret: {secretName: orders-postgres} ``` The Secret appears a few seconds after the push. A pod that starts earlier waits for it and starts on its own once it is there. **Migrations stay a Job.** Jobs are not allowed in `deploy/`, so your coding agent runs the migration as its own Job through `nyx_deploy_manifests`, with the `-migrate` Secret. A framework that migrates on boot fails with the app role, which is the separation working. Move that step into the Job. **Sharing a database.** One app declares it, others read it. A second app that declares a database of the same name is refused. It reads the first app's Secret with `envFrom` instead, and its page shows the database as "used, declared by <app>". ## A bucket: `deploy/bucket.yaml` On instances with object storage, a bucket is one more file. Elsewhere the push is refused before anything is written, with "object storage is not set up on this instance". Buckets are available on instances on AWS and STACKIT. On AWS every bucket is created with encryption at rest (SSE-S3) and with public access blocked. ```yaml # deploy/bucket.yaml apiVersion: nyxory.com/v1alpha1 kind: Bucket metadata: name: reports spec: versioning: false credentials: auto ``` | Field | Values | |---|---| | `versioning` | `true` or `false` (default), `true` keeps overwritten objects | | `credentials` | `auto` (default), `keys` or `identity` | | `secretName` | optional, defaults to `-s3`, fixed after the first push | | `deletionPolicy` | ignored, data from the repo is always kept | `auto` picks the strongest access the instance offers. On AWS that is `identity`, where the app reaches the bucket through the identity of its pod and no key exists anywhere. On other providers it is `keys`, an access key pair in the Secret. A mode the instance does not offer puts the bucket into an error with reason `CredentialsUnavailable` and never falls back quietly. For access by identity the pod runs under the app's own ServiceAccount, which carries the app's name: ```yaml spec: serviceAccountName: web containers: - name: web image: IMAGE_REF envFrom: - secretRef: {name: reports-s3} ``` The Secret `reports-s3` carries the same names in both modes, so the app code does not change between them: | Key | Holds | Mode | |---|---|---| | `S3_BUCKET`, `S3_REGION`, `S3_ENDPOINT` | bucket name, region, endpoint | both | | `S3_FORCE_PATH_STYLE` | `false` on AWS, `true` where the endpoint is path-style | both | | `AWS_REGION`, `AWS_ENDPOINT_URL_S3` | region and endpoint under the names AWS SDKs read by themselves | both | | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY` | the access key pair | `keys` only | Build the S3 client with the SDK's default credential chain and read only the bucket name. The chain finds the key pair in `keys` mode and the pod identity in `identity` mode. ```python import os, boto3 # region, endpoint, credentials: the default chain s3 = boto3.client("s3") s3.put_object(Bucket=os.environ["S3_BUCKET"], Key="hello.txt", Body=b"hi") ``` ```js import { S3Client, PutObjectCommand, } from "@aws-sdk/client-s3"; const env = process.env; const s3 = new S3Client({ forcePathStyle: env.S3_FORCE_PATH_STYLE === "true", }); await s3.send(new PutObjectCommand({ Bucket: env.S3_BUCKET, Key: "hello.txt", Body: "hi", })); ``` In `identity` mode, pods that were already running when access was set up get restarted once by the platform, and the bucket shows "waiting for access" meanwhile. The boundary is the project. Every app in the project reaches the project's buckets, and no app in another project does. Bucket names on AWS are global, so a name taken elsewhere ends in reason `BucketNameTaken`, and a different `metadata.name` fixes it. ## Data from the repo is kept Databases and buckets declared in `deploy/` belong to the project, not to the app: - **Removing the file keeps the data.** The app page shows "No longer in deploy/, last declared in <commit>. The data stays." - **Deleting the app keeps it too.** Other apps that read its Secret keep working. - **`deletionPolicy: Delete` in the file is ignored**, and the app page notes it. - **Checks run before anything is written.** nyxory checks the per-project limit for databases and buckets, that the Secret name is free, and that `tier` and `secretName` of an existing database are unchanged. Deleting is its own, deliberate step, for workspace owners and admins. On the app page, **Delete database** or **Delete bucket** asks you to type the name to confirm, or your coding agent does the same with `nyx_data` (`type: postgres` or `type: bucket`) after your approval. A bucket is emptied and removed. A database is dropped after a final dump, and on an instance without a dump target it stays until one is set up, which the dialog tells you. Take the file out of `deploy/` first, otherwise the next push creates the object again, empty. A database or bucket your coding agent created earlier for this app is taken over when `deploy/` declares it with the same name, the same Secret and, for a database, the same tier. From then on `deploy/` owns it, and changes go through the repo. ## Postgres with a client certificate Optionally, a database logs in by client certificate instead of a password: ```yaml spec: tier: shared auth: certificate ``` Neither role has a password any more. Each pod of the declaring app gets a client certificate for its role, mounted as files under `/etc/nyxory-postgres-cert` and never stored in a Secret. The certificate lives 72 hours and the platform replaces it after 48. On an instance that does not offer certificate login, the database reports reason `CertificateAuthDisabled` and nothing changes. The Secrets change shape. `PGPASSWORD` is gone, `DATABASE_URL` carries `sslcert` and `sslkey`, and `PGSSLCERT` and `PGSSLKEY` point at the two files. A Deployment in `deploy/` that reads the Secret with `envFrom` gets the certificate volume, the CA mount and the app's ServiceAccount added automatically, so the `envFrom` line stays the same as with a password. The platform adds them on a push once the database exists. When the database and the Deployment arrive in the same first push, push once more after the database is ready. A connection that is open keeps working when the certificate rotates. Every new connection has to present the current file, and drivers differ in how they read it: | Driver | Reads the new certificate | What to do | |---|---|---| | libpq: `psql`, psycopg 2 and 3, Django, SQLAlchemy on psycopg, Rails `pg` | on every connect | nothing, `DATABASE_URL` or `PGSSLCERT`/`PGSSLKEY` as they are | | node-pg (`pg`) | on every new client built from `connectionString` | pass `connectionString: process.env.DATABASE_URL` and do not read the files into an `ssl` object once at start | | pgx (Go) | never, `ParseConfig` loads the files once | clear `TLSConfig.Certificates` and set `GetClientCertificate` to load `PGSSLCERT` and `PGSSLKEY` with `tls.LoadX509KeyPair` on each call, otherwise the pool fails once the first certificate expires | | pgjdbc (Java, Spring, Hikari) | on every new physical connection | pass `sslrootcert`, `sslcert` and `sslkey` from the environment on the JDBC URL | | asyncpg, Prisma, npgsql | not verified | stay on `auth: password` | In certificate mode a database is not shared. Only the app that declares it receives the certificate for the app role, and the migration Job runs under a ServiceAccount named like the migration Secret, `orders-postgres-migrate`, which the platform creates for it. Since the Job goes through your coding agent and not through `deploy/`, it carries that `serviceAccountName` and the certificate volume itself. Switching between `password` and `certificate` is a change in the file, and roles keep their data and grants. The certificate volume follows the mode the database had when the push was applied, so push once more after the database reports the new mode, in either direction. **Why a certificate and not a token.** Postgres checks credentials only when a connection opens, and most drivers and pools read the password once at start, so a token that changes every hour breaks on the next reconnect. A certificate is read from disk when a connection opens, which is exactly when Postgres checks it, and Postgres verifies it natively. ## Not in `deploy/` yet - settings only one provider knows, such as your own encryption key or retention periods for a bucket - rolling out the same change to several instances at once - several apps in one repository, each with its own `deploy/` Tell us which you need. Related: [Deploy on push](/docs/guides/auto-deploy) · [Storage and backups](/docs/guides/storage-and-backups) · [Deploy from a private repo](/docs/guides/deploy-from-a-private-repo) --- # Day-2 operations Source: https://nyxory.com/docs/guides/day-2-operations.md There's no separate "update" toolset. Every day-2 operation — a new image, a config change, a secret rotation, a scale-up — runs through the same `nyx_*` tools as the first deploy, just combined differently. (For *watching* an app rather than changing it — logs, resource usage, traffic — see [Monitoring](/docs/guides/monitoring).) ## Change, restart, scale, inspect - **Ship a new image build (same source, rebuilt).** Your agent calls `nyx_build_and_push_image` again — it returns a fresh `image_ref` with an auto-incrementing `-N` suffix — then `nyx_deploy_manifests` with just the updated Deployment document, `app_manifest` left out so the tool resolves the app's UID from the cluster on its own. - **Change a ConfigMap, Service, or Ingress.** Same path: `nyx_deploy_manifests` with the changed document, `app_manifest` omitted again. - **Rotate a secret.** `nyx_set_secret` writes the new value, then `nyx_shell` runs `kubectl rollout restart deployment/ -n ` so the pod picks up the new ciphertext — the same command covers a plain restart with no spec change. - **Scale.** Either `nyx_shell` with `kubectl scale deployment/ --replicas=N -n ` for a one-shot change, or `nyx_deploy_manifests` with an updated Deployment YAML to make it persist. - **Inspect.** `nyx_app_list` / `nyx_app_get` for the app-level overview, `nyx_app_get` with `view: deployments` for the ReplicaSet rollout history, and `nyx_shell` with read-only `kubectl get ... -o ...` for anything else. - **Delete.** A single resource goes through `nyx_shell` (`kubectl delete / -n `); a whole app goes through `kubectl delete app/ -n `, and the ownerRef cascade removes everything it owns, volumes and buckets included. To keep data, see [Storage and backups](/docs/guides/storage-and-backups#volume-or-bucket-and-what-happens-on-delete) before you delete. > **Note:** When `app_manifest` is omitted, `nyx_deploy_manifests` reads the `app.kubernetes.io/instance` label off each document, confirms they all belong to the same app, resolves that app's UID in the cluster, substitutes ``, validates ownerRefs, then applies. If the app doesn't exist yet, this fails with `app-not-found` and `app_manifest` becomes required. ## Multiple apps per project A project can host any number of apps — a Compose monorepo with frontend, API, and DB, or a web/worker/queue split. Each app gets its own `nyx_deploy_manifests` call with its own `app_manifest`; the tool is atomic per app and doesn't batch across calls. Independent apps can deploy in any order. Dependent apps (an API that needs its DB up first) deploy the dependency, then wait on it before deploying the dependent app: ```bash kubectl wait --for=condition=Ready pod -l app.kubernetes.io/instance= -n --timeout=25s ``` Keep each wait under roughly 25 seconds and re-poll on timeout — a single long timeout or sleep loop won't survive the MCP client's own timeout. If the plan creates more than one workload pod, check RAM and CPU headroom before the first deploy call — the project's quota is shared across every pod in the namespace. For `docker-compose.yml` repos, each service becomes its own App CRD — never one app for the whole compose file. `depends_on` maps directly to deploy order. Compose `environment` blocks become either a project-scoped secret (shared values) or a per-service app secret. For Helm charts: render with `helm template`, inject the standard labels and ownerRefs, then `kubectl apply`. Skip `helm install` directly — it bypasses the App CRD ownership model and leaks resources when the app is later deleted. ## Service discovery An app reaches a sibling app in the same namespace through that app's **Service name as host** — the short name (`db`) or the FQDN (`db..svc.cluster.local`) — on the Service's `port`, not its `targetPort`. This runs over standard cluster DNS; nothing extra needs provisioning. Never address a sibling app by pod IP (it changes on every restart) or by its public `{{ .AppDomainPattern }}` URL — that would route out to the internet and back through ingress. Database wire protocols return a `502` over that path, and non-HTTP services don't get a public domain at all. Build the connection string from the Service name and Service port, write it with `nyx_set_secret` at project scope so every app in the namespace can read it, and consume it via `envFrom`: ``` DATABASE_URL=postgres://user:pass@db:5432/appdb ``` The same pattern applies to any backing service — only the scheme and port change: - `redis://cache:6379/0` - `mongodb://mongo:27017/appdb` - `amqp://mq:5672` - `http://api:8080` for an internal HTTP API (keep the port unnamed / non-HTTP to stay off ingress) For separate host/port env vars, use `host = ` and `port = `. Cross-namespace calls need the FQDN; same-namespace calls only need the short name. ## Next steps - **[Add a custom domain →](/docs/guides/add-a-custom-domain)** — bind your own hostname - **[Deploy a Next.js app →](/docs/guides/deploy-a-nextjs-app)** — first deploy walk-through --- # Deploy a Next.js app Source: https://nyxory.com/docs/guides/deploy-a-nextjs-app.md The whole path, end to end: point your coding agent at a Next.js repo and have it live on nyxory in about five minutes. You write one prompt; the nyxory agent does the deploy — build, secrets, image, rollout — and hands back a URL. No Dockerfile to write, no manifests to hand-edit. > **Prereqs** > - Your agent is connected to nyxory — see [Connect your agent](/docs/getting-started/connect-your-agent) > - A Next.js repo (Pages Router or App Router, both fine) > - Some headroom in your account — your agent checks this for you ## 1. Open the repo, then ask Open the Next.js project in your connected editor and say what you want: > deploy this Next.js app to nyxory To send it to a specific project, name it: > deploy this Next.js app to my "widget" project on nyxory ## 2. Let it work From here it's hands-off. Your agent pulls the recipe for a Next.js app and works through the deploy — and you see each step as it happens: - it clones the repo into an isolated workspace off your machine (private repo? it hands you a one-time [GitHub App install](/docs/guides/deploy-from-a-private-repo) link) - it inspects `package.json` and your environment, and asks which values are secrets versus build-time embeds - it builds a container image and rolls it out Any of these can pause for a quick question — an ambiguous secret, a non-standard build script, an unfamiliar dependency. You're not driving the deploy; you're approving it. ## 3. Watch it land When the deploy resolves, your agent returns a URL like `https://widget-.nyxory.app`, and the app appears in the console — live, with its [resource usage and traffic](/docs/guides/monitoring). Watch it from whichever side you prefer: ```bash nyx app list # everything you're running nyx app get widget my-nextjs # one app, including its live host nyx app logs widget my-nextjs # container logs, no kubectl hop ``` Or open **Projects → widget → Apps** in the console. ## 4. Verify it's live Read the host from `nyx app get`, then probe it: ```bash nyx app get widget my-nextjs --json | jq -r '.data.domains[0].host' curl -I https://my-nextjs-.nyxory.app ``` Expect `200 OK`, or just open it in your browser. (`nyx app verify widget my-nextjs` runs the probe for you.) ## Getting Next.js right > **Tip:** > > - **`output: 'standalone'`** in `next.config.js` produces a smaller, faster-starting container. Highly recommended — your agent will set it for you if it isn't already. > - **Env vars as secrets vs build-time embeds.** `NEXT_PUBLIC_*` vars are baked into the client bundle; everything else stays server-side. Your agent asks you which is which when it detects ambiguity in `.env`. > - **Static asset paths under a path prefix.** If you've configured `basePath` or `assetPrefix`, double-check the ingress host matches — broken images are usually a `basePath` mismatch. > - **Image optimization.** Next's image loader needs `unoptimized: true` or a remote loader config if you don't want runtime image processing in the pod. ## Next steps - **[Add a custom domain →](/docs/guides/add-a-custom-domain)** — bind your own hostname - **[Deploy on push →](/docs/guides/auto-deploy)** — redeploy automatically on every git push - **[Monitoring →](/docs/guides/monitoring)** — resource usage, traffic, and logs - **[Deploy from a private repo →](/docs/guides/deploy-from-a-private-repo)** — one-time GitHub App install --- # Deploy from a private repo Source: https://nyxory.com/docs/guides/deploy-from-a-private-repo.md Private repos deploy like public ones once nyxory can read them. How it reads them depends on where the repo lives: | Where the repo lives | How nyxory reads it | |---|---| | **github.com** | The **nyxory GitHub App**: a one-time install in your browser, then short-lived tokens. No deploy key, no PAT. | | **Any other Git host** (GitLab, Bitbucket, self-hosted) | An **HTTPS Git connection**: a service account's username and access token, stored once per workspace. | | **Gerrit connected to your instance** | A **read account per project**: no token at all, the repository owner grants each project in Gerrit. | All three work on every plan. > **Prereqs** > - An agent connected to nyxory (see [Connect your agent](/docs/getting-started/connect-your-agent)) > - For GitHub: admin access to the repo or org you want to connect > - For other hosts: you own the workspace, and you have a service account with read access to the repo ## GitHub 1. **Just prompt.** ``` deploy https://github.com/me/private-widget to nyxory ``` Your agent calls `nyx_brain`, then tries the clone. For a public repo that's the end of the story. For a private one, the clone bounces with an auth error. 2. **The agent hands you an install link.** On the bounce, the agent calls `nyx_github_install_url` and gives you a signed install URL. The link expires after **10 minutes**. If it goes stale, the agent just mints a fresh one; the call is idempotent. 3. **Install the app in your browser.** Open the link, pick the repositories you want nyxory to reach (or select the whole org), click **Install**. It's a regular GitHub App: repo-scoped, visible under your GitHub settings, revocable there at any time. You can also start the install from the console: **GitHub** in the workspace menu. 4. **Tell your agent you're done.** It retries the clone via `nyx_clone_repo`. The repo lands in your project workspace and the deploy continues exactly like a public-repo deploy. If several installations cover the same owner, the agent disambiguates with `nyx_github_list` (installations, then `kind: repos`). Builds clone the repo with a short-lived installation token (about an hour) that your Dockerfile never sees. Details in [Builds & the execution surface](/docs/concepts/builds-and-the-execution-surface). **Sharing in a workspace.** A repo you deploy in a shared workspace is added to the workspace's shared repositories automatically, so members can deploy it in their projects with your GitHub access. The owner manages that list under **Team → Shared repositories** and can remove a repo there. ## Other Git hosts over HTTPS For GitLab, Bitbucket, or a self-hosted Git server, the workspace owner connects the repository once in the console: 1. Open **GitHub** in the workspace menu. With HTTPS connections available, the page is titled **Git connections**. 2. Under **Other Git repositories**, click **Connect repository** and fill in a name, the **Repository URL (HTTPS)**, the **Service account username**, and its **Access token**. An expiry date for the token is optional; the console shows it next to the connection. 3. Decide who may use it: **Share with workspace** lets every member deploy the repo in their projects; otherwise it stays **Owner only**. 4. **Check main** verifies the credentials can read the repo before anyone builds from it. After that, prompt as usual. Your agent clones with `nyx_clone_repo`, passing the connection's `connection_id`, and builds use the saved credentials for their clone step. Set an expiry and rotate the token on your side; nyxory doesn't shorten its lifetime. - Sign-in uses the username and the token together; a token alone is not enough. The service account only needs read access. - The saved token is never displayed again. **Edit credentials** replaces it, **Disable connection** stops new builds through it while running apps stay up. - SSH deploy keys for other hosts are not supported. Use HTTPS with a token. - Auto-deploy works for these repos too: nyxory checks the watched branch about once a minute and builds each new commit. See [Deploy on push](/docs/guides/auto-deploy). > **Note:** HTTPS Git connections are on for every workspace on the shared nyxory platform. On a dedicated instance they are switched on per instance. ## Gerrit: one read account per project If your instance is connected to a Gerrit server, the Git connections page names it, and repos there need no token. Instead, **every project that uses a Gerrit repository gets its own read-only Gerrit account**, which signs in over SSH with a key the console generates. The account can read nothing until the repository owner grants it.
Step 3 is the only one a person does, and only once per project and repository.
1. **Connect the repository.** The workspace owner uses **Connect repository** as above. For a Gerrit URL the form asks only for a name and the URL: no username, no token. 2. **Deploy as usual.** On the first deploy the clone is refused: the agent reports the project's account and a link to the repository's access settings in Gerrit. 3. **Grant it.** The repository owner opens the link and, under **Access**, grants **Read** on `refs/*` to the group with the account's name. 4. **Clone again.** Tell your agent it's granted; it retries `nyx_clone_repo` and the deploy continues. Once auto-deploy is set up for the app, its **Auto-deploy** panel shows the same state: **Waiting for approval** with the account and an **Open access in Gerrit** link, then **Reads over SSH as** the project's account. A grant made while the panel waits is picked up within a minute, without asking the agent. Because each project has its own account, granting one project a repository never opens it to another project, in the same workspace or elsewhere. See [Projects & accounts](/docs/concepts/projects-and-accounts#isolation-between-projects). ## Managing access ``` which GitHub accounts are connected to nyxory? ``` Your agent lists them via `nyx_github_list`. Revoking is a person's call, not your agent's: - **From the console:** **GitHub** in the workspace menu lists the installations connected through nyxory, with a disconnect action per installation. - **From GitHub:** Settings → Applications → Installed GitHub Apps → nyxory → Uninstall. Same effect. After any of these, no new tokens can be minted for that installation. Outstanding short-lived tokens age out within the hour. For HTTPS connections, **Disable connection** on the Git connections page is the revoke. For Gerrit, the repository owner removes the group's **Read** grant in Gerrit. ## Troubleshooting > **Caution:** > 1. **The install link 404s or errors.** It expired (10-minute window). Ask your agent for a fresh one: `nyx_github_install_url` re-signs on every call. > 2. **Installed, but the clone still fails.** Check the repo was actually included in the installation: ask your agent to run `nyx_github_list` with `kind: repos` for the installation. The repo's `full_name` must appear there. If you picked "selected repositories" during install, add the missing repo from GitHub's app settings. > 3. **Multiple orgs, wrong account.** The install link binds to whichever GitHub account you're logged into. Log into the right account (or use the org picker on GitHub's install screen) and re-open a fresh link. > 4. **Org requires approval.** In orgs where you're not an admin, GitHub queues the install as a request. The clone succeeds as soon as an org admin approves the request. That approval lives on GitHub's side, so nudge the admin rather than re-running the install. > 5. **HTTPS connection shows "Access failed" or "Credentials expired".** The token was revoked, expired, or lacks read access. **Edit credentials** with a fresh token, then **Check main** again. > 6. **Gerrit clone still refused, or the panel stays on "Waiting for approval".** The grant is missing or went to the wrong group. The group name is exactly the account name in the error or on the panel. > 7. **Still stuck?** Ask your agent for the exact clone error and the output of `nyx_github_list`. That pair is what we'll ask for in support. ## Next steps - [Deploy a Next.js app](/docs/guides/deploy-a-nextjs-app): the full deploy walk-through - [Deploy on push](/docs/guides/auto-deploy): redeploy on every commit to the watched branch - [Builds & the execution surface](/docs/concepts/builds-and-the-execution-surface): where the build token story comes from --- # Jobs and CronJobs Source: https://nyxory.com/docs/guides/jobs-and-cronjobs.md Some work isn't a server. A migration before a cutover or a nightly database dump starts, does its job, exits `0`, and is done. A **Job** runs once; a **CronJob** runs on a schedule. Your agent deploys either one the same way it deploys an app. ## Deploying one Two steps, the same as any app minus the server parts: 1. **Build the image.** `nyx_build_and_push_image` from your repo — the same build path. 2. **Deploy the manifest.** `nyx_deploy_manifests` with the Job or CronJob spec. Like every object the app owns, it carries the App ownerReference and the app's `app.kubernetes.io/instance` label. A Job or CronJob gets **no Service, no domain, and no probes** — there's nothing to route traffic to and nothing to health-check. The only signal that matters is whether the run completed. ## Scheduling recurring work A CronJob runs a container on a schedule you set, which makes it the workhorse behind day-to-day operations an agent sets up once and then leaves running: - A **nightly database backup** to your object store (on the shared platform, backups are otherwise on demand, see [Storage and backups](/docs/guides/storage-and-backups#backups-and-restore)). - An **hourly data-consolidation or sync job**: pull, transform, write, exit. - A **periodic cache warm** or cleanup pass. Your agent writes the schedule (`spec.schedule` in standard cron syntax) and applies it; from there the container fires on its own. The work in the container is yours to define — the CronJob just guarantees it runs on time. With [auto-deploy](/docs/guides/auto-deploy) on, a push reaches CronJobs too: nyxory rolls the new image into the CronJob's template, and the next scheduled run uses it. A one-off Job is not updated this way; its pod template can't change, so rerun it yourself. ## Verifying a run Don't wait for a `1/1 Ready` pod and don't curl anything — neither ever comes. Check completion status, then read that pod's logs for the actual result. > **Note:** A Job is healthy when `status.succeeded: 1`. A CronJob is healthy when `lastSuccessfulTime` is after `lastScheduleTime`. A still-running pod means "in progress," not broken; a pod that's disappeared means "already finished," not failed — completion status is what tells them apart. ## Making it safe to re-run The platform doesn't make re-runs idempotent — the job's own logic has to, because a redeploy or a missed tick can run the work twice. Guard it: append-only writes, skip-if-done checks, `INSERT ... ON CONFLICT DO NOTHING`, or a migration tool that tracks which versions already ran. Two spec settings keep a schedule from causing damage under load — a firing CronJob draws on the same namespace RAM/CPU quota as any running Deployment, so set real `requests`/`limits` on it too: - **`concurrencyPolicy: Forbid`** (or `Replace`) stops overlapping ticks from stacking up if one run outlasts its interval. - **`backoffLimit`** caps retries so a broken job can't spawn pods indefinitely. Relevant tools: `nyx_build_and_push_image`, `nyx_deploy_manifests`, `nyx_shell` (for `kubectl delete job/` and status/log reads). --- # Monitoring Source: https://nyxory.com/docs/guides/monitoring.md Every app is observable the moment it's live, with nothing to install. You look in the console; your coding agent reads the same data over MCP. ## Resource usage Live CPU and memory against the app's allocation, as a 24-hour graph: usage versus the request floor and the limit ceiling. It shows whether an app is comfortable or hitting its ceiling, which is what you need to [size a project](/docs/guides/scaling-and-ram). Your agent reads the same numbers with `nyx_project_state`. ## Traffic For every app that serves HTTP, the traffic panel tracks four numbers:
5,639
Requests · 24h
0.1%
Error rate
95 ms
Latency · p95
28 MiB
Bandwidth
Traffic numbers are in the console only; there is no MCP tool for them yet. Watch error rate and p95 latency: a climbing error rate or a latency spike is usually the first sign of a regression, and because every deploy is on the record, you can line a spike up against the change that caused it. ## Logs For the detail behind a metric, read the app's logs: the project's **Logs** page in the console (live tail of one app), or `nyx_app_logs` from your agent, which returns structured, timestamped lines and handles a scaled-to-zero app cleanly. It's also where you confirm a [Job or CronJob](/docs/guides/jobs-and-cronjobs) did its work. Look for `Exception`, `panic`, `Connection refused`, `OOMKilled`, or a failing readiness probe. ## Availability and operations `nyx_app_get` with `view: uptime` returns daily availability, up to 90 days back. `nyx_ops_events` returns what the platform detected in the project and what it did about it. Every app's image is also CVE-scanned automatically, see [Security scanning](/docs/guides/security-scanning). ## Agent runs If agents run in your project, `nyx_runs` lists their runs, newest first, each with status, duration, cost, and the platform's one-word verdict (`loop`, `budget80`, `baseline:2.1x`). With `run` set to one of them, it opens that run step by step with its alerts and the project's typical run for comparison. Both views tell you where a run went wrong; they store what each tool was called with, not what it returned, so read the error itself with `nyx_app_logs`. --- # Run an agent Source: https://nyxory.com/docs/guides/run-an-agent.md An agent on nyxory is an app like any other: it is built from a repo, runs in your project's namespace, and shows up in the console. Three things are specific to agents. ## Start from the template Ask your coding agent to call `nyx_agent_scaffold`. It returns the files to write and the manifest for a headless agent runtime with the `nyx run` wrapper, which records every run. Deploy it like any app (`nyx_brain` → build → `nyx_deploy_manifests`). Use a CronJob for scheduled agents, a Deployment for always-on ones. ## Models through the AI gateway Apps on nyxory call models through the AI gateway. The first model call creates the gateway application for your app; there is no key to put in the code. `nyx_ai_models` lists the available models with provider, region and price; `nyx_ai_apps` shows your gateway applications with budget and lock state (never key material); `nyx_ai_calls` lists single calls with model, tokens, cost and latency — metadata only; prompts and outputs are not stored by default. ## Budget per agent `nyx_budget_set` sets an advisory monthly budget for one app or the whole project; it is shown in the console and under `account.budgets` of `nyx_project_list`, and nothing is stopped by it. What stops model calls is the gateway application's own budget (`nyx_ai_app`, `action: set_budget`): a locked application gets its model calls refused, the app keeps running. ## Every run on the record `nyx_runs` lists an agent's runs with status, cost and verdict. The console shows the same under the app. What runs on the shared platform: everything above. The operations agent that handles day-2 operations runs on [dedicated instances](/docs/concepts/dedicated-instances). --- # Scaling and RAM Source: https://nyxory.com/docs/guides/scaling-and-ram.md RAM is the one dial. Set a project's RAM in 256 MB steps and its CPU cap follows; there is no separate CPU setting. ## Scaling RAM Your agent reads and sets it over MCP: 1. **Read the state.** `nyx_project_state ` returns `allocatedMb`, `reservedMb`, `floorMb`, and `remainingPoolMb`: what's allocated, what running pods hold, and what's free in the account pool. 2. **Size from the repo, not a guess.** The framework, sidecars, and ML libraries tell you what the workload needs. 3. **Set it.** `nyx_project` with `action: ram` and `mb: ` rounds up to the next 256 MB step. The CPU cap rises with it. The CPU cap is derived from RAM at `allocatedMb * 500 / 1024` millicores, summed across every pod in the project: | RAM | CPU cap | |---|---| | 256 MB | 125m | | 512 MB | 250m | | 1024 MB | 500m | If the account pool has no room, shrink another project or have a person book RAM packs in the console. Never half-apply a deploy that's short on RAM. Every project and app shows live memory and CPU against its allocation, so you size from what actually runs:
Memory · 24h3.4 GB used · 4 GB allocated
Memory actually used Allocated to the project
## What changes the bill Three numbers are easy to mix up. Only the first one costs money beyond your plan:
Example: a Starter account with an 8 GB baseline and two booked RAM packs. Lowering an allocation frees room in the pool; only releasing a pack lowers the bill.
- **Your plan fee** covers the baseline pool (8 GB on Starter, 48 GB on Business). - **RAM packs** add 1 GB each to the account pool at €5 per month, billed by the day you hold them (at least one day). A person books and releases them under **Settings → Subscription** in the console, within the spend limit you set there. Your agent can read the pool (`nyx_project_list`) but not book packs. - **Project allocations and pod usage** only divide the pool. Lowering an allocation with `nyx_project` (`action: ram`) frees room in the pool for other projects; `kubectl scale` or deleting an app frees room inside the project. Neither changes the bill. To save money after a peak: lower the project allocations with `nyx_project` (`action: ram`), then release the packs you no longer need. The console refuses a release while allocations still need that capacity. ## Scaling out: more than one replica Vertical scaling covers most workloads. To run several replicas behind one Service: - **Stateless tiers scale freely.** No local state between requests (no SQLite on disk, no local uploads, no in-process sessions) and no PVC, or only an `emptyDir`. Set `replicas` as high as the project's RAM allows. - **Stateful tiers stay single-replica or go StatefulSet.** App PVCs are `ReadWriteOnce` and bind to one node, so a second replica on another node can't mount the volume and sits in `ContainerCreating`. Databases, caches, and queues run at `replicas: 1`; real HA is a StatefulSet with one PVC per pod plus app-level replication. The access mode is set when the volume is provisioned; editing the Deployment can't widen it. Rule of thumb: **scale the stateless tier out, the stateful tier up.** Shared read-write storage across replicas isn't offered to apps today. ## Sizing a pod Size small web pods around 50 to 100m CPU; don't copy a flat `"1"` or `"200m"` from elsewhere. Every container needs `requests` and `limits` for CPU and memory: - **Deployed with `nyx_deploy_manifests`**, a container without them gets small defaults filled in (requests 50m / 64Mi, limits 100m / 128Mi), and the tool says so. Treat that as a floor and set real values. - **Applied any other way** (for example `kubectl apply`), a container without limits is refused by the project's quota. - **`limits.cpu` over the cap** fails with `exceeded quota: limits.cpu` (`FailedCreate`); no pod is created. > **Note:** Shrinking a project's RAM below what its running pods reserve fails with a 409 (`below_reserved`), returning `requestedMb`, `reservedMb`, and `floorMb`. Delete an app first, or pick an `mb` value at or above `floorMb`. ## Limits outside the dial - **Pod count per project** is capped by plan. - **Storage** comes from a separate pool: your plan's storage plus storage packs (100 GB each), not from RAM. - **`LoadBalancer` / `NodePort` services** are always 0; the ingress is the one way in from outside. See [Projects & accounts](/docs/concepts/projects-and-accounts) for how workspaces, projects, and the pool relate. --- # Security scanning Source: https://nyxory.com/docs/guides/security-scanning.md Every image your builds push is scanned for known CVEs, and every stored image is re-scanned nightly, so a vulnerability published after you shipped still shows up. The console lists what you can fix, next to runtime hardening checked live against your app. ## Always scanned, stays fresh
On push
Every image build is scanned as it lands in the registry — no pipeline step to add, no scanner to configure.
Every night
All stored images are re-scanned against the updated CVE database — new disclosures surface by morning.
Fix-first
The report leads with what you can act on: each CVE with the package and the version that fixes it.
Scanning runs at the registry level, against the image your app actually runs — the same artifact, not a copy of your repo. A freshly pushed image shows **pending** until its first scan completes, then **scanned** with a timestamp, so you always know how current the report is. ## Reading the report The project's **Security** page summarizes each app's scan by severity and lists every fixable finding:
16
Fixable
5
High
9
Medium
2
Low
Each row is one CVE: severity, the affected package, the installed version, and the version(s) that fix it — linked to the advisory for the full story. The list is deliberately filtered to findings **with a fix available**, because that's the actionable set: a report you can work through, not a wall you scroll past. Your coding agent reads the same report over MCP with `nyx_app_security`, and gets one thing more: each finding says whether it sits in your own dependencies (fix it in the lockfile) or in the base image or toolchain (fix it with a newer base image). If the build attached no bill of materials, the tool says so, and an empty list then means "nothing visible", not "clean". To fix findings, hand the list to your coding agent: it bumps the dependency or base image, rebuilds with `nyx_build_and_push_image`, and redeploys. The new image is scanned on arrival, so the next report shows whether the fix landed. ## Hardening, verified live The same page shows each app's runtime hardening — and these are **live checks computed from the namespace's actual state**, not a static claims list. For your app: - **Egress lockdown** — no path into private networks: RFC1918 ranges (10/172.16/192.168) blocked, only DNS and the internet. - **IMDS / metadata block** — the cloud metadata endpoint (169.254.0.0/16) is unreachable, closing off credential theft via IMDS. - **Resource quota & limits** — CPU, RAM, and storage are capped, so no noisy neighbors and no resource escalation. These flip green when the enforcing NetworkPolicies and quotas are actually applied to your namespace — still provisioning shows as exactly that. On top sit two platform-wide guarantees that hold for every app: the **NET_RAW** capability is dropped cluster-wide fail-closed with **seccomp** on the runtime default profile, and the shared platform is **hosted in Switzerland** (Infomaniak), covered by the EU adequacy decision; a dedicated instance runs in the region you choose. Every sub-processor and its location is listed in the [DPA](/dpa). ## Who acts on findings On self-operated projects you do: the report is on the **Security** page, refreshed nightly, and there is no alert yet when a new CVE lands on one of your images. On **operated plans**, CVE response is nyxory's job, run on your plan's credits and written up on the record. --- # Storage and backups Source: https://nyxory.com/docs/guides/storage-and-backups.md Anything that has to keep its data across restarts, a database, an upload directory, a queue, gets a **persistent volume**. On top sits a **backup and restore engine** that snapshots a whole app on demand and rolls it back in three modes. Stateless apps need nothing from this page. ## Persistent volumes A container's own filesystem is scratch space: restart or reschedule the pod and anything not on a volume is gone. Durable storage is a **PersistentVolumeClaim mounted at the app's real data directory**. Your agent adds it to the Deployment and nyxory provisions it from your project's storage pool. The default shape is a single-replica Deployment plus one PVC. When you need stable per-pod identity and DNS for replication or clustering, use a StatefulSet with a headless Service (`clusterIP: None`) and per-pod storage via `volumeClaimTemplates`. **Getting it right on first init:** - **Size from 10 GB up.** Each PVC needs at least 10 Gi, and a PVC can be grown later but never shrunk. - **Point databases at a subdirectory.** A fresh PVC already contains `lost+found`, and the official Postgres, MariaDB, MySQL, MongoDB, and Elasticsearch images refuse to initialize into a non-empty directory. Use a subfolder, e.g. `PGDATA=/var/lib/postgresql/data/pgdata`, or a `subPath` on the mount. - **One node per volume.** App PVCs are `ReadWriteOnce`, so a PVC-backed pod stays at one replica. See [Scaling and RAM](/docs/guides/scaling-and-ram#scaling-out-more-than-one-replica). ## Volume or bucket, and what happens on delete
Both belong to the app and go with it by default. Opt out per resource before you delete, not after.
**Deleting an app deletes the volumes and buckets it owns.** To keep a volume, deploy it with the label `nyxory.com/retain-on-delete: "true"` and without an ownerReference to the App; it then stays when the app goes and keeps counting against your storage pool until you delete it (`kubectl get pvc -l app.kubernetes.io/instance=`). To keep a bucket, set `deletionPolicy: Retain`. A database or bucket declared in the repo's `deploy/` folder is different: it belongs to the project and stays when the app goes (see [Configure your app from the repo](/docs/guides/configure-from-the-repo)). Take a backup before deleting anything you might want back: a `full` restore works even after the app is gone. ## Backups and restore Every app can be **backed up on demand**: a point-in-time, crash-consistent capture of its volumes (CSI snapshots), plus its manifests and the exact image it was running. Take one before a risky migration or a release. Backups fill your plan's keep-N slots (three on the free tier, more on paid plans), each with trigger, size, phase, and image on the record. Use the console (**Backups** page, or the backups on an app's page) or your agent over MCP: `nyx_backup` with `action: create` takes one, `nyx_backup_list` lists them. **Restore** runs through `nyx_backup` with `action: restore` or the console in one of three modes: - **`data`**: roll the volumes back in place, app definition untouched. - **`app`**: roll the image and definition back, data left as-is. - **`full`**: the whole app, also after the app was deleted. Every restore first takes a safety backup. `app` and `full` restores switch [auto-deploy](/docs/guides/auto-deploy) off so a push can't race the rollback; switch it back on in the app's **Auto-deploy** panel when you're ready. > **Scheduled backups.** On the shared nyxory platform, backups are on demand today; for a nightly copy, run your own CronJob (a nightly dump to your bucket, see [Jobs and CronJobs](/docs/guides/jobs-and-cronjobs)). On a dedicated instance, nightly backups can already be switched on for your instance; the app's backup list shows each run with its trigger. ## Object storage **On the shared nyxory platform, bring your own bucket.** Store the credentials of any S3-compatible endpoint (AWS S3, Cloudflare R2, GCS, Backblaze B2) as a project or app secret and consume it with `envFrom`. Never bake keys into an image or ConfigMap. A `Bucket` resource is not provisioned there: `nyx_deploy_manifests` reports it as unsupported, so remove it from the manifest and wire your own bucket instead. **On a dedicated instance with object storage, declare a `Bucket`** next to the app's volumes and Deployment. If the app repo has a `deploy/` folder, the bucket goes there as `deploy/bucket.yaml` and is kept on every push, see [Configure your app from the repo](/docs/guides/configure-from-the-repo). ```yaml apiVersion: nyxory.com/v1alpha1 kind: Bucket metadata: name: uploads spec: deletionPolicy: Delete # default; Retain keeps the bucket and its data when the resource goes versioning: false # default; true keeps overwritten objects ``` nyxory creates the bucket and sets up access in the strongest mode the instance offers (`spec.credentials`, default `auto`). On AWS the app reaches the bucket through the identity of its pod, with no key anywhere; the pod runs under `serviceAccountName: `, and every app of the project reaches the project's buckets, no app of another project does. On other providers the bucket gets **its own access key** and a bucket policy that refuses every other key, including the keys of other projects. The connection values land in a Secret named `-s3` in the same project; the app takes the whole Secret with `envFrom`: | Key | Value | |---|---| | `S3_ENDPOINT`, `S3_REGION`, `S3_BUCKET` | Where the bucket lives | | `AWS_REGION`, `AWS_ENDPOINT_URL_S3` | The same, under the names AWS SDKs read by themselves | | `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` | This bucket's own key pair, only in key mode | | `S3_FORCE_PATH_STYLE` | `true` where the endpoint is path-style, so set your S3 client to path-style or requests fail with DNS errors. `false` on AWS. | Build the client with the SDK's default credential chain and the same code works in both modes. - **Five buckets per project** by default. Capacity is not capped; object count and size are measured about every 15 minutes and shown on the resource. - **Versioning is a bucket's only backup.** App backups never see object storage. Self-hosting MinIO as an app also works: it's a stateful pod with its own PVC from your storage pool, and its backups are yours to run. ## Export your data From an app's page in the console, **Export** snapshots the volume, moves it to object storage, and hands back a time-limited download link. No ticket needed. The export covers the app's volume data; your manifests live with your agent and your repo. Export is available from the Starter plan up. Secret values are not shown again once saved, in the console or by `nyx_set_secret`. Workloads and your agent inside the same project can read them; no other project can. Keep your own copy of anything you'll need outside nyxory. --- # nyx CLI reference Source: https://nyxory.com/docs/reference/cli.md `nyx` is the command-line client for nyxory. It manages projects and apps from your terminal. Many of the same operations are also exposed to a coding agent — Claude Code, Cursor, Codex — as `nyx_*` MCP tools it drives to deploy on your behalf (see the [MCP tools reference](/docs/reference/mcp-tools)). Every command supports `--json` for scripting and CI. ## Global flags These apply to every command. | Flag | Description | |---|---| | `--json` | Emit one JSON envelope per invocation (stdout on success, stderr on error). | | `--context ` | Override the active context for this invocation. Also settable via the `NYX_CONTEXT` environment variable. | | `--version` | Print the CLI version. | The `NYX_TOKEN` environment variable supplies a bearer token in place of the OS keyring — useful for CI. > **Note:** wherever a command takes a `` argument, it accepts three forms — the full namespace (`nyx-abc123`), the bare ID (`abc123`), or the human display label. An ambiguous label returns a `project_ambiguous` error. ## nyx login `nyx login [--api ] [--console ] [--hostname ] [--context ]` Signs in via a browser using OAuth 2.0 loopback redirect (RFC 8252) and stores a long-lived API token in the OS keyring (Keychain on macOS, libsecret on Linux, Wincred on Windows), keyed by context. Sets the target context active on success. - `--api ` — API base URL. Defaults to the target context's stored URL, or the production API. - `--console ` — Console base URL. Same default rule as `--api`. - `--hostname ` — Name recorded for the token. Defaults to the machine's hostname. - `--context ` — Context to log into and activate. Defaults to the current active context, or `prod` on a fresh install. Fresh installs come pre-seeded with `prod` and `dev` contexts, so `nyx login` and `nyx login --context dev` need no `--api`/`--console`. > **Note:** `nyx login` opens a browser and blocks up to 5 minutes waiting for the callback — it isn't headless-safe. For CI or a headless machine, set the `NYX_TOKEN` environment variable instead (bypasses login entirely), or mint a token on a logged-in machine with `nyx token create` and ship it via `NYX_TOKEN`. ## nyx setup `nyx setup [--all] [--client ] [--skip-login] [--no-auto-approve]` Wires every MCP-capable AI client on the machine (Claude Code, Cursor, Codex, VS Code, Claude Desktop) to the nyxory MCP endpoint (`/mcp`) in one pass, signing in first if no token is stored. Each client connects directly over HTTP and performs its own OAuth — the CLI never mints or embeds a token. - `--all` — wire every detected client without prompting. - `--client ` — wire only the listed clients (`claude`, `cursor`, `codex`, `vscode`, `claude-desktop`), even if undetected. - `--skip-login` — fail instead of starting the browser login when no token is stored. - `--no-auto-approve` — don't pre-approve nyxory tool calls in the wired clients. Interactive by default: prompts a checklist of detected clients to wire, and asks Claude Code specifically whether to use the web or local install. Pass `--all` (or `--client ...`) together with `--json` or a non-TTY shell to skip every prompt; without `--all` in that mode the command errors with `confirmation_required`. Claude Desktop always needs a manual step — `nyx setup` prints the connectors URL to paste into claude.ai, since there's no local config file to write. Re-running is idempotent: it overwrites the nyxory registration in place and preserves every other MCP server already configured in each client. ## nyx account `nyx account ` Account-level subscription and resource pool. One subcommand today. ### nyx account ram `nyx account ram` Shows the account-wide RAM pool: plan baseline, extra packs, and how much is already allocated across all projects. Run it before deciding whether a project's allocation (`nyx project ram`) can be bumped. No flags beyond global. Output: plan / plan ID, status, baseline RAM (or "unlimited" on Enterprise), RAM packs (1 GB each), account pool total, storage cap, add-ons, and an upgrade URL when one applies. ## nyx app `nyx app ` Read-only inspection of deployed apps. Every subcommand here only reads state — apps are created by your coding agent calling the `nyx_brain` MCP tool, not by this CLI. ### nyx app list `nyx app list` (alias: `nyx app ls`) Lists apps (App custom resources, not raw Kubernetes Deployments) across every project you own. No flags beyond global. ``` nyx app list --json | jq '.data.items[] | select(.phase != "Available")' ``` ### nyx app get `nyx app get ` Shows one app's detail: phase, replica counts, image, public ingress domains. Both arguments are required. ### nyx app deployments `nyx app deployments ` (alias: `nyx app rollouts`) Shows rollout history, one row per ReplicaSet/revision. ### nyx app logs `nyx app logs [--tail ] [--since ] [--container ] [--pod ] [--grep ] [--previous]` Tails an app's container logs directly, without a `kubectl` hop. Lines are RFC3339-timestamped; a clean message prints if no pod is running. | Flag | Default | Description | |---|---|---| | `--tail` | `200` | Max lines to return | | `--since` | — | Only lines newer than this relative duration (e.g. `15m`, `1h`) | | `--container` | pod's first container | Which container to read | | `--pod` | newest replica | Which pod to read | | `--grep` | — | Case-sensitive substring filter | | `--previous` | `false` | Read the previous, crashed container's logs | ### nyx app verify `nyx app verify [--timeout ]` Probes an app's public ingress domains with an HTTP GET and reports status + latency per host. A probe counts as "ok" below status 500. Exits non-zero if any probe is unhealthy, so it chains in CI: ``` nyx app verify foo bar && deploy-prod ``` - `--timeout ` — per-probe HTTP timeout. Default `10`. ## nyx brain `nyx brain [--project ] [--agent-briefing ]` Hidden command — it doesn't show in `nyx --help`. This is the CLI mirror of the `nyx_brain` MCP tool your coding agent calls to fetch a deploy cookbook: a POST to `/api/brain/deploy` returns markdown guidance plus a scan of the repo and the target project's current state. The agent reads the cookbook and drives the `nyx_*` primitives itself — there's no in-pod planner and no streaming. > **Note:** humans normally don't type this command directly; it exists for local debugging of what the agent sees. - `--project ` — project to fetch the cookbook for. Falls back to the `.nyxrc` found by walking up from the current directory; if left empty and unresolved, the server returns a generic cookbook. - `--agent-briefing ` — free-form context (stack, components, deploy intent, env vars). Pass `-` to read the briefing from stdin. **`.nyxrc`** — drop a TOML file with `project = "widget"` at a repo's root to set the default `--project`. A per-app `.nyxrc` in a monorepo shadows the top-level one. ## nyx context `nyx context ` Manages which nyxory stack (prod, dev, local-stack, or a custom one) the CLI talks to. A context bundles an API URL, a console URL, an identity, and a bearer token. Fresh installs come pre-seeded with `prod` (active) and `dev`. ### nyx context list `nyx context list` Lists every configured context; the active one is marked `*`. No flags beyond global. ### nyx context use `nyx context use ` Sets `` as the active context, persisted to `config.toml`. Errors `context_not_found` if the name isn't configured. ### nyx context show `nyx context show` Prints the resolved active context — name, API URL, user email, user ID, hostname, whether a token is present. The quick answer to "which stack am I on?" ### nyx context remove `nyx context remove ` (alias: `nyx context rm`) Deletes the named context from the config and its OS-keyring token entry. Idempotent — a missing keyring entry isn't an error. If the removed context was active, the active context reverts to `prod`. > **Note:** unlike `project delete`, `domain remove`, and `token delete`, this command has no `--yes` flag and never prompts — it deletes immediately. ## nyx claude `nyx claude ` Wires or unwires Claude Code to the nyxory MCP via `claude mcp add --transport http` — a direct remote endpoint; Claude Code performs its own OAuth, no token is embedded. ### nyx claude install `nyx claude install [--scope user|local] [--no-auto-approve]` - `--scope` — `user` (all projects) or `local` (this project only). Default `user`. - `--no-auto-approve` — don't pre-approve nyxory tool calls. Requires the `claude` CLI on `PATH` (errors `claude_install_failed` otherwise). Also strips legacy artifacts from older `nyx` versions — the old `@nyxory` subagent file and a legacy `SessionStart` hook entry, both superseded by the MCP server's own init instructions. Pre-approval writes a wildcard allow rule into Claude Code's `settings.json`; destructive tools stay server-gated regardless. ### nyx claude uninstall `nyx claude uninstall [--scope user|local]` - `--scope` — default `user`. Runs `claude mcp remove --scope `, strips the permission rules, and removes the legacy subagent file plus (user scope only) the legacy hook. "Not registered" is treated as a clean, non-error outcome. ## nyx codex `nyx codex ` Wires or unwires Codex CLI to the nyxory MCP by editing `~/.codex/config.toml`'s `[mcp_servers.nyxory]` table directly — other servers, settings, and comments are preserved. ### nyx codex install `nyx codex install [--no-auto-approve]` - `--no-auto-approve` — don't pre-approve nyxory tool calls. On a TTY, immediately triggers Codex's own browser OAuth (`codex mcp login`), since Codex doesn't prompt for it on its own. Off a TTY, prints the manual `codex mcp login nyxory` instruction instead. ### nyx codex uninstall `nyx codex uninstall` No flags beyond global. Reports whether an entry was removed. ## nyx cursor `nyx cursor ` Wires or unwires Cursor to the nyxory MCP by editing `~/.cursor/mcp.json` (or `./.cursor/mcp.json` with `--scope local`) directly — there's no `cursor mcp add` CLI to shell out to. ### nyx cursor install `nyx cursor install [--scope user|local] [--no-auto-approve]` - `--scope` — `user` (`~/.cursor/mcp.json`, all projects) or `local` (`./.cursor/mcp.json`). Default `user`. - `--no-auto-approve` — don't pre-approve nyxory tool calls. Best-effort fetches the MCP tool catalog to populate Cursor's `autoApprove` list. ### nyx cursor uninstall `nyx cursor uninstall [--scope user|local]` - `--scope` — default `user`. ## nyx vscode `nyx vscode ` Wires or unwires VS Code (GitHub Copilot agent mode) to the nyxory MCP by writing the user-profile `mcp.json` directly. ### nyx vscode install `nyx vscode install` No command-specific flags. VS Code has no per-server approval mechanism yet, so there's no `--no-auto-approve` on this command. ### nyx vscode uninstall `nyx vscode uninstall` No command-specific flags. ## nyx domain `nyx domain ` Manages custom hostnames on apps (HTTPS via cert-manager and Traefik). A domain moves through `RoutingPending → CertPending → Ready`; in `--json` output, `next.action` tells you which state to wait for (`wait_routing`, `wait_cert`, `ready`, or `failed`). ### nyx domain add `nyx domain add --app [--project ] [--service-name ] [--service-port ] [--path-prefix ]` Registers a custom hostname against an app; the response includes the CNAME (and, if applicable, an apex A record) to point DNS at. `` must be a real RFC-1123 subdomain — no wildcards. | Flag | Required | Description | |---|---|---| | `--app ` | yes | App to route the hostname to | | `--project ` | no | Project owning the app; needed if the app name is ambiguous across projects | | `--service-name ` | no | Override which Service the Ingress targets (default: the app's single Service, or one labeled `nyxory.com/primary-service`) | | `--service-port ` | no | Override the Service port (default: the Service's first port) | | `--path-prefix ` | no | Ingress path prefix. Default `/` | ### nyx domain list `nyx domain list [--project ] [--app ]` (alias: `nyx domain ls`) Lists custom and auto-generated domains. Without filters, flattens across every project the token can see. ### nyx domain status `nyx domain status [--watch] [--timeout ]` Shows a domain's phase, conditions, DNS target, and next-action hint. - `--watch` — poll every 5 seconds and exit once the domain reaches `Ready` (or times out / fails). - `--timeout ` — watch deadline (e.g. `5m`, `30s`). Default `10m`. Ignored without `--watch`. `--watch` blocks with a spinner but is headless-safe — it honors `--json` and never opens a TTY prompt. A missed deadline exits non-zero with a `timeout` error code. ### nyx domain remove `nyx domain remove [--yes|-y]` (aliases: `rm`, `delete`) Deletes a domain — cascades the Ingress, Certificate, and TLS Secret immediately via the operator's finalizer. - `--yes` / `-y` — skip the confirmation prompt. Without `--yes` on a TTY, prompts for a typed `yes`. In a non-TTY shell or with `--json` and no `--yes`, the command exits non-zero with `confirmation_required` rather than proceeding or silently skipping. ## nyx project `nyx project ` Manages projects — the Kubernetes namespaces apps deploy into. ### nyx project list `nyx project list` (alias: `nyx project ls`) Lists every project. No flags beyond global. ### nyx project add `nyx project add [--label "..."] [--no-wait]` Creates a new project. `` becomes the display label unless `--label` overrides it; the server assigns a stable `nyx-` namespace, which is the ID every other command expects. - `--label ` — free-form display name. Defaults to the `` argument. - `--no-wait` — return immediately instead of polling (up to 60 seconds) until the project reaches `phase=Ready`. Polls with a terminal spinner by default; use `--no-wait` or `--json` for scripted use — `--json` returns immediately with a `next: poll_project` hint. ### nyx project rename `nyx project rename