Downcity
Services

Service Actions

Understand command, api, and execute in a service action and what each one means in SDK usage

Service Actions

Service actions are the core capability units exposed by a service.

An action can contain three layers:

  • command
  • api
  • execute

The most important one is execute

For SDK users, execute is the fundamental layer.

Example:

readonly actions = {
  ping: {
    execute: async () => {
      return {
        success: true,
        data: {
          ok: true,
        },
      };
    },
  },
};

It is responsible for:

  • receiving structured payload
  • running business logic
  • returning success / data / error

command

command mainly exists for CLI-side mapping.

It is a good place to define:

  • help text
  • commander arguments and options
  • mapping from CLI input into structured payload

api

api mainly exists for HTTP-side mapping.

It is a good place to define:

  • HTTP method
  • route path
  • mapping from HTTP request into structured payload

A fuller example

readonly actions = {
  add: {
    command: {
      description: "add one item",
      mapInput({ args }) {
        return {
          text: String(args[0] || ""),
        };
      },
    },
    api: {
      method: "POST",
      mapInput(ctx) {
        return ctx.req.json();
      },
    },
    execute: async ({ payload }) => {
      const text = String((payload as { text?: unknown }).text || "").trim();
      if (!text) {
        return {
          success: false,
          error: "text is required",
        };
      }
      return {
        success: true,
        data: {
          text,
        },
      };
    },
  },
};

The easiest SDK misunderstanding

The current Agent SDK HTTP server is a session SDK server. It is not a general platform that automatically exposes arbitrary custom service actions.

That means today:

  • the SDK exposes a minimal set of session HTTP routes
  • but writing service.actions.api does not automatically publish that action under agent.start({ http: { ... } })

Likewise, the local SDK Agent is not a wrapper that automatically generates CLI commands for your custom service.

Then why should you still care about command and api?

Because this action contract is part of the broader Downcity service model.

Its value is:

  • custom services keep the same shape as full runtime services
  • if you later move toward fuller service-manager integration, your mental model survives
  • today you can still treat execute as the core layer, with command and api as extension points

The most practical SDK advice

If you are doing pure embedded local SDK work, focus first on:

  • execute
  • instance state
  • lifecycle

Treat command and api as:

  • extension slots in the shared service contract