diagridio/catalyst-ai

catalyst-deploy

Move an application from a laptop into Diagrid Catalyst.

View source

How to use

  1. Copy the installation command and review the source package before installing it in your own agent environment.
  2. Check the source document for required tools, credentials and supported hosts.
  3. Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/diagridio/catalyst-ai --skill catalyst-deploy

Before you start

  • Installation does not include a model subscription, API allowance or permission to access your files.
  • Repository stars and installation counts describe activity, not an independent quality or security test.
Original skill document

Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.

Get an application running in Catalyst

Goal: end this skill with a named resource the user can open in the console, whose readiness you confirmed by reading it back rather than by watching an apply succeed. An apply that returns is an apply that was accepted; it is not a thing that works.

Order matters throughout, and not as a matter of taste — several of the constraints below leave a resource permanently broken when taken out of order, with no error at the moment you got it wrong. Read sections 1 and 3 before creating anything.

How to deploy: catalyst_apply

Every create and change goes through catalyst_apply. You send manifests, and it creates what does not exist and replaces what does. It accepts these kinds: Project, Configuration, Component, Pubsub, KVStore, Resiliency, HTTPEndpoint, Subscription, Agent, MCPServer, App, WorkflowAccessPolicy, MCPServerAccessPolicy and TokenBudget.

It is listed only for users whose role can write. If it is missing, that is the user's role, not a broken connection: tell the user a write role is needed and stop. There is no other route to create a resource.

  • Send one application's resources together, with one exception. Within a call it

applies them in a fixed order: project, configurations, components and subscriptions, agents and MCP servers, apps, then access policies and token budgets. That puts a subscription before the apps, but section 3 requires the identities a subscription scopes to to exist first. So send subscriptions in a second call, after the call that created their apps, agents or MCP servers. Across calls, the order is yours to get right.

  • Call `catalyst_get_resource_schema` before writing a kind for the first time. Do

not guess field names: the platform rejects unknown fields, and a guessed name that happens to be accepted can mean something else.

  • Run it with `dry_run` first and show the user what will be created or replaced.
  • Replace means replace. To change an existing resource, read it with its get tool,

change it, and send it back whole: a field left out is dropped.

  • Settings read back without a value are refused, not erased. At the default

metadata data-sharing level a read withholds inline setting values, such as a component's spec.metadata. Sent back as they are, the call fails with "nothing was applied" and lists each setting. Ask the user for each value, or better, point the setting at a secret with secretKeyRef so the value never passes through the conversation. Never delete the entry to get past the check: that removes the stored setting on replace.

  • The first failure stops the batch. Everything after it is reported as not

attempted. Fix that one and send the rest again; applying the same manifests twice is safe.

  • Accepted is not ready. Read each resource back (section 5).

Deleting goes through catalyst_delete_resource, never as a side effect of a deploy. It cannot be undone. Every kind except a project is deleted on the first call, so ask the user before you call it, and name what goes with the resource. A project is the one exception: the first call returns a preview of everything it would remove, plus a confirmation token. Show the user that preview, and call again with the token only after they agree.

1. Budget the headroom first

Do this before designing a topology, not after building one. Every cap here is enforced at create time, so the cost of discovering one late is a redesign rather than a retry.

  • catalyst_get_usage reports used and limit per key.
  • catalyst_get_metrics reads request rates, error rates and consumption for a project

or a single app, agent or MCP server.

Read the numbers. Do not recite remembered plan values — organizations get custom limits, so a figure from memory is often wrong for the one in front of you.

The scope of each cap is the part people get wrong

CapScopeConsequence for a design
number_of_appids — Identities: one per app, agent and MCP serverPer region, summed across every project in the organizationSplitting a topology across two projects does not buy more
number_of_connectionsPer region, org-wideSame. A connection is a component
number_of_catalyst_subscriptionsPer region, org-wideSame
number_of_projectsPer regionLow, and easy to spend by accident — see section 7
number_of_pubsubs_per_projectPer project1 on every plan
number_of_kvstores_per_projectPer project1 on every plan

Two of those deserve stating out loud because they change what you build:

Apps, agents and MCP servers all consume the same allowance. Each is backed by one identity, and identities are what the quota counts. The rejection says so, and names the breakdown: "has reached the maximum of N resources for its ... region ..., currently using N (...). Each agent, MCP server, and app counts toward this limit." A coordinator plus four specialists plus one MCP server is six of them. The remedy in that message is to contact Diagrid support, not to change plan — do not tell the user an upgrade fixes it without checking.

One managed pub/sub and one managed KV store per project, on every plan. It is a platform default rather than a free-tier restriction, and no plan upgrade raises it. (A negotiated per-organization override does exist, so if a live quota read disagrees with the 1, trust the live read.) A multi-service or multi-agent design therefore separates traffic by topic on the one broker and by key prefix in the one store. Design for that from the start; presenting it as a limitation to work around produces a design that cannot be built. Read catalyst_get_usage for every other figure rather than quoting one.

Finally, headroom is not the only per-region property. Managed pub/sub, managed KV and the Workflows API are regional capabilities, and a region that lacks one gives you a project where that API simply is not available. catalyst_get_region says what the region supports. If workflow calls must work, confirm the region supports them before you build on them.

There is no quota page in the console. Do not link to one; report the numbers.

2. The app, agent or MCP server comes first, because it carries the identity

Apps, agents and MCP servers are each backed by an identity (an "App ID" in some APIs). Where a tool asks for or returns appId, it means that identity's name. Read it from the resource's status.appIds (the get tools include it). For an agent registered from your own code, it's the appId on its registry record.

The identity is not a deployment artifact. It is what the sidecar runs under: it owns the API token, it is what components are scoped to, it is what a subscription delivers to, and it is what a local connection attaches to. Nothing can reference an application whose resource does not exist yet, which is why every ordering constraint in section 3 starts from it.

Names are unique across three resource types in a project. Creating an agent whose name is taken by an app fails with "the name ... is already in use in project ...; App, Agent and MCP server names must be unique within a project". Pick the name once, for the right resource type, and check catalyst_list_apps and catalyst_list_agents before you do.

Which kind to apply

DeployingKindWho owns the identity
Your own applicationAppThe app you just made
An agent whose code you run yourselfAgentThe agent provisions and manages its own
An MCP serverMCPServerThe MCP server, likewise

Read catalyst_get_resource_schema for the fields each takes. An App takes an endpoint and an endpoint token; an Agent takes an endpoint and archive settings.

An endpoint is optional. Created without one you get an identity that Catalyst can route from but not to, which is exactly what an app running as a pure worker wants. Set one only when the app runs a server there for Catalyst to call. With the app's health check enabled, while nothing answers it the app's workflows, actors and message delivery stay blocked.

The agent resource

Agent fronts an agent your application runs. An application that runs itself — locally, in a container, anywhere — uses `Agent` for that. There are no model settings on it, and looking for one is the signal that you have the wrong resource.

3. Ordering constraints, and the mechanism behind each

Each of these has a reason, and the reason is what tells you whether a failure is recoverable.

Create thisBefore thisBecause
The managed workflow store on the projectAny app, agent or MCP server that uses workflowsThe sidecar reads workflow configuration at boot. One created first comes up without workflow support and the Workflow API answers FAILED_PRECONDITION. Enabling the store afterwards does not retrofit the running sidecar
Components and subscriptionsThe app, agent or MCP server that consumes themSo they exist when the sidecar boots and loads them
A ConfigurationThe app that names it via appConfigThe reference has to resolve at create time
The Agent or MCP serverAnything else of that nameThis one does not self-heal. An Agent or MCP server will not adopt a same-named identity it does not own, so anything else created first under that name leaves it permanently in an error state. There is no repair short of deleting what took the name
The apps, agents or MCP servers a subscription scopes toThe subscriptionScopes must already exist in the project and already have access to the broker

catalyst_apply orders one call for you as described above, but it cannot order two calls, and it cannot fix a workflow store enabled after the app.

4. Attach the connections

A component exists in the project; it reaches an application by being scoped to that application's identity. Apply a Component with its spec.scopes set:

  • scopes is the attachment. **Leaving it empty grants every app, agent and MCP server

in the project access**, which is convenient and is also how a component ends up loaded by a sidecar nobody intended.

  • Types are pubsub.*, state.*, bindings.*, secretstores.* and conversation.*.
  • When you do not already know the metadata keys a type expects, read

catalyst_get_resource_schema and catalyst_list_templates rather than guessing them.

Managed services have fixed names — pubsub for the broker, kvstore for the KV store. The managed workflow store is wired in implicitly and has no component name, so do not go looking for one.

Access between applications is a separate control from both, and it is deny-by-default: a caller that no policy names is refused. Grant it with catalyst_grant_access, and take it away with catalyst_revoke_access. Read the current policy first with catalyst_get_access_policy: the first grant on an App with no policy creates one that denies everyone else. Both directions change who can reach the app, so say what will change and get the user's agreement before either call: a grant can widen access to every caller (*), and a revoke breaks the caller's calls as soon as the policy reaches the sidecar.

Subscriptions are the pub/sub half: apply a Subscription naming the pubsub component, the topic, the route, and the identities it is scoped to.

Four component facts that each cost a rebuild when missed:

  • A component's type is immutable. Changing it fails with `component must be deleted

to be updated as the component type cannot be changed once created, and converting to or from a Diagrid managed type fails the same way with its own wording. Delete it with catalystdeleteresource` and apply it again, with the user's agreement first; there is no in-place path.

  • `actorStateStore` is rejected on a managed state store. The managed workflow store

already fills that role.

  • `agent-registry` is managed by Diagrid. Do not create or edit it.
  • `agent-` components require a matching Agent resource**, because the control plane

needs one to scope the registry store to the sidecar. Components without their Agent are a hard failure, not a warning.

5. Verify readiness, do not infer it

An apply returning is the beginning of the check, not the end of it. Read the resource back:

  • catalyst_get_app, catalyst_get_agent, catalyst_get_mcp_server and

catalyst_get_component. The first three include the backing identity under status.appIds, which is where its readiness lives.

  • For the components and subscriptions attached to it, catalyst_list_components; read

each one's scopes.

Ready is not one field. Catalyst's own readiness check requires the identity's status to be ready and its API token to be present; a status of ready with no token yet is not usable, and that is the state a caller most often reports as "it says ready but nothing works". No read tool returns the API token; only catalyst_get_connection does (see catalyst-develop section 3).

The status vocabulary is ready, pending, processing, provisioning, updating, deleting, deleted, error, unknown — but the set is not closed and the API declares the field as a bare string, so report the value you were given verbatim rather than rounding it to one of the nine. Agents report from a narrower set — ready, error, pending, or empty before their first reconcile.

Four readings that mislead if taken alone:

  • A component's real reason lives under `status.appIdStatus[]`. A component that fails

to load is only reported as such by the sidecar of each scoped identity, so the resource-level message is often empty while the per-identity one names the broker error. A pub/sub's status.topicError and a KV store's status.itemsError sit outside that structure entirely.

  • A disabled MCP server reports `ready`, with a message saying it is disabled and

loaded by no app. Disabled is a fully reconciled state, so ready is honest — it is just not the answer to "is it serving". Read the message.

  • `updating` right after a local connection attaches is normal. Attaching one makes

the sidecar reconfigure, so the identity goes ready → updating → ready.

  • A missing local connection is not an error. It means nobody is running that app

from a machine right now. catalyst_list_app_tunnels lists the ones that are.

Then prove the path rather than trusting the status. For a workflow app, start a run with catalyst_start_workflow and read it back with catalyst_get_workflow_run; that separates the platform from the application. catalyst_get_metrics shows whether the app has served or sent anything. Invoking the app directly, publishing a test message and reading state back are not available over MCP yet; say so rather than claiming you checked them.

The API token of an app, agent or MCP server is the credential for that identity. No read tool returns it; only catalyst_get_connection does (see catalyst-develop section 3). Do not ask the user to paste one, and do not write one into a summary, a file or a commit.

6. Hand back a link so the user can see it

Once something exists, give the user a way to look at it. Naming a resource you cannot link to is a weaker answer than naming it with a link.

The console for the production server is https://catalyst.diagrid.io. If you cannot build a link you trust, print the identifiers as plain text.

Use only these routes, appended to that host:

ResourceRoute
App/apps/details/:id
Agent/agents/:appId/:agentId
MCP server/mcp-servers/:id
Workflow run/workflows/:appId/:runId, optionally /:tab
Metrics for one app, agent or MCP server/metrics/appids/:id, by identity
Metrics for the project/metrics, or /metrics/appids
Project list/admin/projects

An agent's :agentId is not its name. It is the agent_id on the agent's registry record, from catalyst_list_agents or catalyst_get_agent, and looks like O5SWC5DIMVZC2YLTONUXG5DBNZ2A. Copy it from that answer; a link built from the name opens a page that cannot find the agent. An agent with no registry record yet takes its app ID in both places: /agents/:appId/:appId.

Two pages you may expect do not exist. There is no project detail view — only the list, and /admin/projects/:id/users — and there is no quota page. Linking to either one 404s.

The project rides along as a query parameter, and the two forms do not fall back to one another:

What you are holdingParameterExample
A name-like id?project=<name>?project=default
A numeric uid?projectId=<uid>?projectId=165, prj- prefix optional

projectId wins when both are present. Put a numeric uid into ?project= and the console searches for a project literally named after that number, finds none, and silently shows the user's default project instead — no error, just the wrong data under the right heading. If you cannot tell which form you hold, omit the parameter.

A link that 404s or lands on the wrong project is worse than no link.

7. Do not create a project

Every organization gets one named default, with managed pub/sub, a managed KV store, the workflow store and agent infrastructure already attached. Deploy into it.

It is bootstrapped once, when the organization is first reconciled, and it is not recreated if someone deletes it. Confirm with catalyst_list_projects; if it is genuinely gone, ask which project to use rather than inventing one. A hand-made project that behaves differently is indistinguishable from a broken one to the person asking for help.

Be careful with a Project manifest in a catalyst_apply batch: it creates the project it names, so check its metadata.name. A project argument that differs from it is rejected. Send one only when the user has explicitly asked for a new project.

Rules

  • Use the Catalyst MCP tools for everything in Catalyst.
  • Name the organization before the first write. Before the session's first

catalyst_apply, catalyst_delete_resource or any other call that creates, changes or deletes something, call catalyst_whoami and tell the user which organization the change lands in. A user with more than one organization cannot otherwise tell where it went. If it fails, follow catalyst-setup and write nothing.

  • Check headroom before designing, not after building. catalyst_get_usage.

Identities, connections and subscriptions are capped per region across the whole organization, so a second project adds no headroom for them.

  • Never offer an upgrade as the fix for the single pub/sub or KV store. It is 1 on

every plan, so no plan change buys a second one. Read the live quota rather than asserting the 1. Describe the shape that works — one broker with many topics, one store with many key prefixes.

  • Do not offer a second project as the way to get a second broker or store. Each project

carries its own, but a second one spends a project slot (read catalyst_get_usage) and splits one app into two environments. The intended shape is one broker separated by topic; if you mention a second project at all, say that.

  • Never suggest an upgrade to clear a cap. Read the limit, and if it is genuinely

reached, the platform's own remedy is to contact Diagrid support.

  • Say `app` or `agent`, never just "agent". They are different resources with

different settings, creation paths and console routes.

  • Create the Agent or MCP server before anything else of that name. It will not adopt

an identity it does not own, and is then permanently in error.

  • Dry-run first, and verify by reading the resource back. An apply that returned is

not a resource that works, and ready without an API token is not ready.

  • Report a status verbatim. The vocabulary is not closed, and paraphrasing a platform

error loses the detail that mattered.

  • Do not create a project. Use default, and check the metadata.name of any

Project manifest in a batch.

  • Ask before any delete. catalyst_delete_resource cannot be undone.
  • Do not print secrets. Never paste a secret value, or an API token if you are ever

given one, into anything that outlives the answer.

  • Link only what you can link correctly, with a route from section 6 and a project

parameter whose form you are sure of.

from this repository

More skills

All skills