diagridio/catalyst-ai

catalyst-develop

Run an app or agent locally against Diagrid Catalyst — get its connection with catalystgetconnection, start it, trigger runs, and crash and restart it to watch a workflow resume.

Ver código fuente

Cómo usar

  1. Copia el comando y revisa el paquete antes de instalarlo en tu entorno de agente.
  2. Consulta las herramientas, credenciales y entornos necesarios en el documento original.
  3. Describe las entradas y el resultado deseado; contrasta la salida con las fuentes.
npx skills add https://github.com/diagridio/catalyst-ai --skill catalyst-develop

Antes de empezar

  • La instalación no incluye suscripción al modelo, cuota API ni permisos sobre tus archivos.
  • Las estrellas e instalaciones reflejan actividad, no una prueba independiente de calidad o seguridad.
Documento original del Skill

Contenido del repositorio de origen con títulos, ejemplos, código, tablas, enlaces e imágenes preservados.

The local development loop

Goal: end this skill with the user's own process running on their machine, talking to a real Catalyst sidecar, and able to see what it did. A loop that requires a redeploy per edit is not this loop; if you find yourself recreating resources to test a code change, something above is wrong.

Everything here goes through the Catalyst MCP server, the catalyst_* tools. If they are missing or refuse with NOT_AUTHENTICATED, the catalyst-setup skill covers it.

1. The shape of the loop

FrequencyStepHow
Once per appMake sure the App ID exists, with its componentscatalyst_get_app, else catalyst_apply (section 2)
Every run of the processGet the connection values and start the process with themcatalyst_get_connection (section 3)
Every iterationTrigger a run and read what happenedcatalyst_start_workflow, catalyst_get_workflow_run (section 4)

What survives an iteration: the app and its identity, its API token, the components, the subscriptions, the managed pub/sub and KV store. What you redo: your process. Nothing in a code change requires touching the platform, and section 6 lists what does force a change. Read it before you delete anything.

Never create a project to develop in. Every organization gets one named default with managed pub/sub, KV, workflow store and agent infrastructure already attached. Confirm with catalyst_list_projects, and pass the project on every call; there is no current project. A Project manifest creates the project it names, so if one is in a batch, check its metadata.name; a differing project argument is rejected. Send a Project manifest only when the user explicitly asked for a new project.

2. Make sure the App ID exists

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.

  1. catalyst_get_app for the project and the app name. If it exists and is ready, go

on.

  1. If it does not exist, create it with catalyst_apply: read

catalyst_get_resource_schema for the App kind first, run with dry_run and show the user, then apply. The project's managed pubsub and kvstore are already there. Apply a component only if the app needs one beyond them, and apply it before the app, then any subscriptions scoped to the app in a second call (see catalyst-deploy for the full ordering), so they exist when its sidecar boots. An agent needs none: apply its Agent resource and Catalyst provides its state, pub/sub and registry (catalyst-agent-scaffold). A sample's local resources/ files are for running without Catalyst, so leave them out. An app with no endpoint is the correct shape for a pure workflow worker, which dials Catalyst outbound.

  1. Read it back and wait for ready. updating right after a local connection attaches

is normal; give it time before calling it broken.

catalyst_apply is a write tool. If it is absent, the user's role cannot write: say so and stop.

3. Running the app locally

The app runs as the user's own process with three values in its environment. Catalyst hands them out through one tool.

  1. Make sure the App ID exists (section 2).
  2. Call catalyst_get_connection for that project and App ID. For an agent or an MCP

server, pass the App ID behind it: one tool serves all three. It returns DAPR_API_TOKEN, DAPR_GRPC_ENDPOINT and DAPR_HTTP_ENDPOINT. It is a write-consent tool and its calls are audited, so the client may ask the user to approve it.

  1. Start the process (the app, agent or MCP server) with those three values in its

environment, in whichever of these ways your shell tool allows. Run it yourself, in the background:

  • Inline on the command:
     DAPR_API_TOKEN=<token> DAPR_GRPC_ENDPOINT=<grpc> DAPR_HTTP_ENDPOINT=<http> APP_ID=<app-id> uv run main.py
  • A `.env` file in the app's folder. The quickstart samples don't read .env

themselves, so load it into the process's environment when you start it: with uv run --env-file .env main.py, or with set -a; . ./.env; set +a in the same shell before the run command. Make sure .env is listed in .gitignore, and add it if it isn't.

  • Your tool's own environment option, if it has one.

Use the user's own run command in place of uv run main.py, and the app's own port or server flags if it has any (a web app started with uv run uvicorn main:app --port 5001 for example). A pure workflow worker dials Catalyst outbound and needs no inbound port.

  1. These are local-dev values, not production secrets. A deployed app gets its own

injected by the platform. Never paste DAPR_API_TOKEN into the chat, a pull request, an issue or a commit. Beyond that it needs no special handling.

  1. On a crash or a restart, reuse the same environment. If the token is no longer in hand,

call the tool again.

  1. If catalyst_get_connection is missing or refused, say that it is unavailable to

this role or server, and stop. There is no other route to these values.

Two things about the worker process itself:

  • A worker needs only those values. A process that registers workflows and activities

and polls for work items dials Catalyst outbound. It needs no tunnel and no inbound port. Do not add an HTTP server just so that a port has something to answer: the worker then registers the workflow and every activity successfully and dies at bind because something else holds the port, and the startup log reads as healthy right up to the error. Do not give it an app port either: --app-port on a tunnel, or a health-checked app endpoint on its App ID, with nothing listening blocks every workflow start (section 7).

  • An app that Catalyst must call into (service invocation, pub/sub delivery, an agent

endpoint, the MCP server behind an MCPServer) needs an app tunnel as well, and these three values do not open one. The catalyst-app-tunnels skill covers it. Never use a public tunnel instead. catalyst_list_app_tunnels lists the tunnels open on the project, so you can see whether Catalyst currently reaches a local process.

  • An app or agent that calls an MCP server calls it through its own sidecar, at

$DAPR_HTTP_ENDPOINT/v1.0/diagrid/mcp/<mcpserver-name> with its DAPR_API_TOKEN. It never calls the server's own URL, and never calls dapr.internal.mcp.* workflows (DaprMCPClient in the Dapr SDK). catalyst-agent-scaffold section 9 has the details.

If the process cannot connect, read the app back (catalyst_get_app) before changing code. Status and the per-identity messages under status.appIds say whether the platform side is ready. Sidecar log reading is at full data sharing only (section 5).

4. Trigger a run, so there is something to read

Nothing above produces anything until a workflow actually runs. Starting one is a write, so catalyst_start_workflow is absent from the tool list for a role that cannot write — if it is not there, that is why.

catalyst_start_workflow takes the project, the app identity and the workflow name, plus the input if the workflow wants one. It assigns the instance id and hands it back.

Capture the instance id. It is how every later call refers to that run — reading its status, its history, or stopping it. Losing it means listing runs and guessing which one was yours, which is ambiguous the moment two runs start in the same second.

Show the run's console link at every step. That means when the run starts, whenever you wait for the user (a crash, an approval, "type continue"), and when it ends. Use the link the tool response gives. If it gives none, build it from the run: https://catalyst.diagrid.io/workflows/<app-id>/<instance-id>?project=<project>. This works for an agent's runs too, with the agent's App ID.

Read the result with catalyst_get_workflow_run: it returns the execution graph, so you see which step the run is on or failed at. catalyst_list_workflow_runs finds runs when you lost the id.

Stopping a run is a separate matter and is deliberately not in this skill — it is irreversible and belongs with diagnosis rather than iteration (catalyst-debug).

Watch a run survive a crash

This is the quickest way to see what durability buys:

  1. Start a run, then kill the process mid-run. Use the sample's crash endpoint if it has

one, otherwise stop the process.

  1. catalyst_get_workflow_run now shows the run RUNNING and waiting for a worker, not

failed. The steps that finished are already in its history.

  1. Restart the process with the same connection values (section 3, step 5).
  2. When the run completes, its history shows that every step that finished before the

crash ran once, and only the step the crash cut off ran again.

That re-run is expected, because activities run at least once. Never say "nothing ran twice". An activity with a side effect must be safe to repeat (catalyst-activity-idempotency).

5. Read the output while you develop

Three different sources, and picking the wrong one is why bugs look invisible.

SourceHowWhat it carries
Your processIts own terminal or log file, where you started itWhatever your code prints. Catalyst never sees it
The runcatalyst_get_workflow_runStatus, the execution graph, step errors. input, output and customStatus are withheld at the default data-sharing level
The sidecar's API logcatalyst_get_logs, at full data sharing onlyOne entry per Dapr API call the app made, with status, method and error

catalyst_get_logs returns DATA_SHARING_RESTRICTED at the default metadata level. That is policy, not a fault: do not retry it, say the logs were not shared at this organization's data-sharing level, and use the other two sources. catalyst_get_metrics shows request and error rates for the app when the question is "is anything arriving at all".

An absent field is not an empty one. Never report a missing output as "the workflow produced no output". Say it was not shared at this level.

6. Iterating without touching the platform

A code change needs nothing but your process restarted: stop it, start it again with the same environment, and the app, components and subscriptions are found rather than made.

What genuinely does require a platform change:

ChangeWhy
A new component or subscriptionIt has to exist before the sidecar that loads it boots
A component's typeImmutable. It must be deleted (catalyst_delete_resource, with the user's agreement) and applied again, and that includes converting to or from a Diagrid managed type
A new appNothing can reference an app that does not exist yet
The app's health-check or protocol settingsAn app's identity spec is not updated in place; read it, change it and apply it whole

A component pointing at a local address is not translated for you: Catalyst components are applied as written, so point state and pub/sub at the project's managed kvstore and pubsub rather than at a local broker.

7. When the worker does not come up

Route by what you actually saw. Guessing here wastes a whole iteration.

SymptomCauseDo
catalyst_get_connection missing or refusedNot available to this role or serverSay so and stop
catalyst_get_app says the app does not existWrong name or projectCheck the name with catalyst_list_apps
The app is not readyStill provisioning, or a component failedRead status.appIds messages; catalyst_list_components and then catalyst-debug
The worker starts but no run ever appearsThe project has no managed workflow store, or the store was enabled after the appRead the project with catalyst_get_project; the sidecar reads workflow configuration at boot, so the app may need re-creating after the store is enabled
The worker is connected but a run failsAn application errorcatalyst_get_workflow_run for the failing step
Every workflow start fails with failed to create workflow instance: context canceledThe worker runs behind an app tunnel opened with --app-port, or its App ID has an app endpoint with the health check enabled, and nothing answers there. Catalyst starts no workflows or actors until the app's health check passesRemove the app port: clear the endpoint on the App ID (read it, drop the endpoint, apply it whole), or run it without --app-port (catalyst-app-tunnels). Keep one only for a process that serves Catalyst's calls
Bind error on startup in a worker that never needed a portAn HTTP server was added unnecessarilyRemove it; see section 3
A component is not readyA component, not your appcatalyst_get_component, then status.appIdStatus[]
component must be deleted to be updated ...You changed a component's typeDelete it and apply it again
agent-* components rejectedNo matching Agent resource existsApply the Agent first; agent-registry is managed by Diagrid, do not create it

Two quieter failure modes with no error to search for:

  • A setting that does nothing. Catalyst applies components as written and ignores

Dapr settings that belong to a self-hosted sidecar. If a setting appears to have no effect, read the resource back before debugging your code.

  • The app is ready and requests still do not arrive. Check

catalyst_list_app_tunnels: with no tunnel open on that App ID, nothing in Catalyst can reach the local process (catalyst-app-tunnels, which can also print requests as they arrive). Then check catalyst_get_metrics for the app.

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.

  • Do not create a project. Use default, and check the project name before the first

call of a session.

  • **Set the connection values inline, in a gitignored .env, or through your tool's

environment option**, and never paste DAPR_API_TOKEN into chat, a pull request, an issue or a commit.

  • Do not fall back to anything else when a tool is missing or refused. Say it is

unavailable to this role or server, and stop.

  • Say which source a line came from. Your process, the run and the sidecar log fail

differently, and a conclusion drawn from the wrong one sends the user to the wrong place.

  • Wait for readiness rather than retrying past it. Re-creating a resource resets its

timers and makes a slow provision look like a hang.

  • Do not delete resources to test a code change. Nothing in an edit-run-observe cycle

needs a component or app recreated.

del mismo repositorio

Más Skills

Todos los Skills