LAB429/ Cheetah product page ↗

Cheetah / Cheetah documentation

Add client actions

A client action combines executable code with an honest description of what the runtime can do. Register handlers and their descriptors before startup so the server receives a complete capability snapshot during connection negotiation.

Register a handler and descriptor

runtime.registerHandler(
  {
    commandType: 'summarize_text',
    async execute(ctx) {
      const text = String(ctx.command.params?.text ?? '');
      return {
        status: 'applied',
        payload: { characterCount: text.length },
      };
    },
  },
  {
    name: 'summarize_text',
    summary: 'Summarize supplied text',
    requiresArgCheck: true,
    argSchema: {
      text: { type: 'string', required: true },
    },
  },
);

The descriptor name should match the handler's commandType. Duplicate command types fail rather than replacing an earlier handler silently. Without a full descriptor, the runtime can advertise only the minimal action name.

Register the complete advertised action and module set before start(). Startup constructs the hello advertisement retained for reconnect. A handler added later can exist in local dispatch and introspection, but the current protocol has no live capability-change message and reconnect reuses the earlier startup advertisement.

Understand the execution pipeline

After the runtime acknowledges a valid command frame, shared client code performs the work around the product handler. Depending on configured providers, it can:

  1. resolve supported payload references and encrypted envelopes;
  2. normalize and validate arguments;
  3. combine the central decision with client-local policy and optional approval;
  4. preflight requested parser definitions;
  5. acquire a lease around the target context;
  6. execute the handler with progress and cooperative cancellation facilities;
  7. perform supported post-action capture;
  8. emit a terminal result or error and release the lease.

An acknowledgement precedes policy and handler execution. It proves that the bound runtime received a valid frame into its dispatch path, not that local permission was granted or that the action completed.

Keep platform ownership honest

The shared runtime should own common lifecycle and protocol behavior. A platform package owns access to its real environment:

  • the browser package coordinates extension lifetimes, tabs, windows, content scripts, capture, and parsing;
  • the console package can expose files, processes, downloads, modules, and long-running flows;
  • the web package cooperates from inside a page and does not inherit extension privileges;
  • native or custom bridges implement their own capability and transport boundary.

Put a handler in the layer that actually owns the required authority. Do not implement a browser action in the server by copying cookies or page assumptions across the network.

Apply authority at both ends

The application can deny work before delivery through central authorization. The client then applies its local policy and any required human approval. Local policy may narrow the central decision but never broaden a denial. An approval permits one invocation; it does not rewrite the policy for future commands.

Descriptors are capability claims, not permission grants. Sensitive actions should use specific parameter schemas, narrow targets, explicit policy rules, and results that do not leak more local data than the application needs.

Return structured outcomes

Return a small structured payload on success and a stable, documented error code on failure. Use progress for meaningful intermediate state, not for a high-volume debug log. If a handler causes an external side effect, include the product idempotency or reconciliation identity in the result whenever possible.

Respect cancellation cooperatively at safe points. A cancellation request or expired server waiter cannot force an operating system, browser page, or external service to roll back work that already escaped.

Add an optional facility