Shimpz

Define one Action per file

A direct actions/*.py file contains exactly one decorated async def run. Its filename, description, parameters, Integration ids, and return annotation become the reviewed contract.

Use a narrow verb and object in the filename

actions/inspect_zone.py python
from typing import TypedDict

from shimpz import Context, action


class ZoneResult(TypedDict):
    zone_id: str
    status: str


@action(
    integrations=["cloudflare"],
    effect="read_only",
    description="Show whether one of your domains is active on Cloudflare.",
)
async def run(domain: str, *, ctx: Context) -> ZoneResult:
    response = await ctx.fetch("GET", f"https://api.cloudflare.com/client/v4/zones?name={domain}")
    zone = response.json()["result"][0]
    return {"zone_id": zone["id"], "status": zone["status"]}
  • inspect_zone.py becomes the Action id inspect-zone.
  • The only decorated function is named run and is asynchronous.
  • integrations=[...] lists only Integration ids declared in shimpz.toml.
  • effect="read_only" declares that the Action has no business side effect; an Action without it is mutating.
  • description="..." is required: one line of 1 to 80 characters that says what the Action does for the person.
  • Typed parameters become required Brain input; ctx is invocation context.
  • The typed return value defines the output the Brain may receive.

The description is shown beside the Action id on the Assistant's page. Write it as a string literal directly in @action(...): the SDK reads it with the message catalog before any Assistant code is imported and refuses a computed value, such as a variable, a concatenation, or an f-string. It joins that catalog and is translated into every interface language, so it must be NFC-normalized English without braces, and every translation must fit 120 characters.

Use the closed annotation subset

Scalar values
str, int, float, and bool.
Closed choices
Literal with unique, non-empty string values.
Collections and objects
list[T] and nested TypedDict. Action results must be a TypedDict.
Optional object fields
NotRequired[T] or Required[T] inside a TypedDict.
Descriptions and constraints
Annotated may add a description and type-appropriate string, number, or list bounds. Parameter defaults, unions, tuples, arbitrary dictionaries, positional-only arguments, *args, and **kwargs are rejected.

Do not hand-write transport or schemas

shimpz.contract.json json
{
  "id": "inspect-zone",
  "description": "Show whether one of your domains is active on Cloudflare.",
  "integrations": ["cloudflare"],
  "stored_inputs": [],
  "input_files": [],
  "human_requests": [],
  "effect": "read_only",
  "input_schema": {
    "type": "object",
    "properties": {"domain": {"type": "string"}},
    "required": ["domain"],
    "additionalProperties": false
  },
  "output_schema": {
    "type": "object",
    "properties": {
      "zone_id": {"type": "string"},
      "status": {"type": "string"}
    },
    "required": ["zone_id", "status"],
    "additionalProperties": false
  }
}

The entry contains the canonical Action id and description, its declared Integrations, Stored Input ids, file inputs, and human-request capabilities, its effect class, and the two closed schemas, plus any declared verifier and idempotency. Every list is present even when empty; an Action declares at most eight Stored Inputs. The Controller addresses the Action by id and validates every input and result against those reviewed schemas; Assistants do not declare HTTP transport.

One Assistant contract contains between 1 and 128 Actions in canonical id order. With SDK 0.5.2, the contract also carries the Assistant's message catalog beside its Actions.