Skip to content

Actions

Actions define executable operations within a document. They are written as fenced code blocks with an act. info string prefix.


An action is defined in a fenced code block whose info string starts with act.:

```act.action_id
TYPE endpoint_or_command
param1: type (constraints) "description"
param2: type (constraints) "description"
```
  • Info string: act. followed by the action ID
  • First line: action type and topic
  • Following lines: parameter definitions (indented)

Action IDs MUST follow these rules:

RuleValidInvalid
Lowercase letterssearchSearch
Numbers allowedget_v2
Underscores allowedsearch_city
Hyphens allowedsearch-city
Must start with a letterdeploy2deploy

Pattern: [a-z][a-z0-9_-]*

Action IDs MUST be unique within a document.


The first line of the code block declares the type and topic.

GET https://api.example.com/search

HTTP GET request. Parameters are sent as query string.

POST https://api.example.com/submit

HTTP POST request. Parameters are sent as JSON body.

PUT https://api.example.com/resource/{id}

HTTP PUT request. Parameters are sent as JSON body. Replaces the entire resource. Standard REST semantics.

PATCH https://api.example.com/resource/{id}

HTTP PATCH request. Parameters are sent as JSON body. Updates specific fields. Standard REST semantics.

DELETE https://api.example.com/resource/{id}

HTTP DELETE request. Parameters are sent as query string (same as GET).

CLI command-name --flag {param}

Shell command execution. Parameters are substituted into the command template.


Each parameter is defined on its own line, indented with spaces:

name: type (constraints) "description"
FieldRequiredDescription
nameYesParameter name
typeYesData type
constraintsNoParenthesized constraints
descriptionNoQuoted description text
TypeDescription
stringText value
numberNumeric value (integer or float)
booleanTrue or false
pathFile path

Constraints appear in parentheses, comma-separated:

ConstraintMeaning
requiredParameter must be provided
optionalParameter may be omitted (default)
value hintsAllowed values, e.g. celsius|fahrenheit
max:NMaximum value or length
min:NMinimum value or length
q: string (required) "Search query"
limit: number (optional, max:50) "Maximum results"
unit: string (optional) "celsius|fahrenheit"
verbose: boolean (optional) "Enable detailed output"
manifest: path (required) "Kubernetes manifest file"

```act.search_city
GET https://api.weather.com/search
name: string (required) "City name to search"
unit: string (optional) "celsius|fahrenheit"
```
```act.create_alert
POST https://api.weather.com/alerts
city: string (required) "Topic city"
condition: string (required) "rain|snow|temp"
threshold: number (optional) "Trigger value"
```
```act.update_alert
PUT https://api.weather.com/alerts/{alert_id}
alert_id: string (required) "Alert ID"
condition: string (required) "New condition"
```
```act.patch_settings
PATCH https://api.weather.com/users/{user_id}/settings
user_id: string (required) "User ID"
unit: string (optional) "celsius|fahrenheit"
```
```act.delete_alert
DELETE https://api.weather.com/alerts/{alert_id}
alert_id: string (required) "Alert ID"
```
```act.deploy
CLI kubectl apply -f {manifest}
manifest: path (required) "Kubernetes manifest file"
```

HTTP actions MAY declare custom headers on the first line using curl-style -H flags:

GET https://api.example.com/data -H "Authorization: Bearer $TOKEN"

Headers are appended after the URL on the first line:

METHOD url -H "Header-Name: value" -H "Another: value"
  • -H "Key: Value" — curl-compatible syntax
  • Multiple headers: repeat -H flags
  • $variable — persistent variable (configuration, credentials)
  • {variable} — session variable (runtime data)
```act.inbox
GET https://gmail.googleapis.com/v1/users/me/messages -H "Authorization: Bearer {access_token}"
maxResults: number (optional)
q: string (optional) "Search query"
```
```act.create_issue
POST https://api.github.com/repos/{repo}/issues -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3+json"
title: string (required)
body: string (optional)
```
  1. Headers appear on the first line only, after the URL.
  2. Each header is a separate -H "Key: Value" flag.
  3. Variable substitution ({var} and $var) applies to header values.
  4. No default headers are injected for actions — only declared headers are sent.

HTTP actions (POST, PUT, PATCH) default to sending the payload fields as a flat JSON object (JSON.stringify(payload)). When the API expects a different body shape — nested objects, specific field names, type wrappers — declare an explicit body template using the body: directive inside the action block.

```act.generate
POST https://api.example.com/v1/generate -H "Authorization: Bearer $API_KEY"
prompt: string (required) "Input text"
filename: string (required) "Output path"
resolution: string "1K, 2K, or 4K" = "1K"
body:
{
"contents": [{"parts": [{"text": "{prompt}"}]}],
"config": {"size": "{resolution}"}
}
```
  • body: is an indented directive line. Continuation lines (indented more than the body: line itself) are part of the body. Blank lines inside the body are preserved.
  • {field} placeholders are substituted from the action’s payload. When a placeholder appears inside a JSON string literal (between "), the value is JSON-string-escaped (quotes, backslashes, control chars, unicode). Outside a JSON string, the value is inserted raw.
  • Modifiers may be appended after a pipe: {field|modifier}.
ModifierEffect
{name|base64}Base64-encode the field value as-is
{name|base64file}Read the value as a file path, base64-encode the bytes
{name|file}Read the value as a file path, insert the file contents

Modifiers compose left-to-right: {name|file|base64} reads the file then base64-encodes the result.

{name|base64file} is the common pattern for binary inputs (images, audio) that would exceed the OS argument-length limit if the caller encoded them inline.

If no body: directive is declared, the runtime sends JSON.stringify(payload) — the remaining payload fields (after URI substitution) serialized as a flat JSON object. This matches the behavior of most simple CRUD APIs:

POST https://api.example.com/resource
title: string (required)
body: string (optional)

Calling /act.create --title "Hello" --body "World" sends {"title":"Hello","body":"World"}.

body: is ignored for GET, DELETE, and CLI methods.


An invocation hint is an inline code span showing how to call the action. It is content, not metadata — it tells the reader (AI or human) what the action looks like when invoked.

`/act.search_city --name "{City Name}"`
`/act.search_city "{City Name}"`

Both forms are valid. Bare values (no leading -) bind to the action’s required fields in declaration order; --name value, --name=value, and short aliases (-n value) are also accepted. A bare -- ends option processing — anything after it is positional even if it starts with -.

Invocation hints are conventional, not parsed by the SFMD format itself. They serve as documentation within the document. Runtime binding rules are described in the runtime actions guide.


An action MAY have a companion response template defined in a separate code block:

```act.action_id.response
template content
```

The info string is act. + action ID + .response.

A response template contains four types of lines, recognized in this order:

1. Assignment lines — store values from the response:

{variable} = {Response.body.field}

A line is an assignment if it matches the pattern: {identifier} followed by = followed by an expression.

Assignment lines are evaluated but produce no output.

2. Save directive — extract a value from the response body into an internal buffer:

save: candidates[0].content.parts[0].inlineData.data

The path walks the JSON response body directly (no Response.body. prefix needed; $. is optional). Array indices ([0], [1], …) are supported alongside dotted keys.

3. Decode directive — reinterpret the buffer extracted by save::

decode: base64

Currently supported: base64, none. After decoding, the buffer holds the decoded bytes.

4. To directive — write the buffer to a file:

to: {filename}

The path supports {field} (action payload) and {var} (session variable) substitution. After writing, no output is produced by default — the author should add an explicit output line for any user-visible success message.

5. Output lines — everything else:

## Weather in {city}
- Temperature: {temp}°C

Output lines are rendered as Markdown with three substitution passes: {Response.body.X} (response data), then {var} (session variables), then {field} (action payload fields — the flags the caller passed). This allows output lines like:

Saved: {filename} ({mime}, {resolution})

where {filename} and {resolution} come from the action’s payload, and {mime} was set by an assignment line earlier.

The three directives form a pipeline for extracting binary data from JSON API responses:

  1. save: reads a JSON path → buffer is a string (the raw value)
  2. decode: base64 converts the buffer → buffer is now bytes
  3. to: {path} writes the bytes to a file

Example: save a Gemini-generated image:

```act.generate.response
{mime} = {Response.body.candidates[0].content.parts[0].inlineData.mimeType}
save: candidates[0].content.parts[0].inlineData.data
decode: base64
to: {filename}
Saved: {filename} ({mime})
```

If save: resolves to undefined (path not found), a warning line is emitted and to: is skipped. If decode: fails, a warning line is emitted. These warnings become part of the output.

```act.search_city.response
{city} = {Response.body.city}
{temp} = {Response.body.temperature}
## Weather in {city}
- Temperature: {temp}°C
- Condition: {Response.body.condition}
- Humidity: {Response.body.humidity}%
```

Response data is accessed using dot-and-bracket notation:

ReferenceMeaning
{Response.body.field}Field from response body
{Response.body.nested.field}Nested field
{Response.body.items[0].name}Array index + field
{Response.body[0].display_name}Top-level array element
{Response.status}HTTP status code
{Response.body}Entire response body

Array indices use [N] syntax and are zero-based. Paths that resolve to undefined (missing key, out-of-range index) produce an empty string in output lines.

Action invocation is “call and read the result” — not navigation. When an HTTP action completes:

  • If a response template is declared, the runtime runs it and returns the output (text lines joined, after all substitutions and file writes).
  • If no response template is declared, the runtime returns the response body as plain text. The current document stays unchanged.

In neither case does the current document switch to the response. The action’s output is rendered in the viewport; the session’s document, history, and shortcuts remain where they were before the call. This means an agent can invoke multiple actions in sequence without re-/open-ing the app between calls.


Action definitions MAY reference variables:

  • {variable} — session variable, substituted at invocation time
  • $variable — persistent variable, substituted by the engine
GET https://api.example.com/search?key=$API_KEY
q: string (required)

See 07-variables.md for variable syntax rules.


Action definition blocks (act.name) and response template blocks (act.name.response) are metadata. In String runtime, they are parsed and registered but not displayed as document content.

In a standard CommonMark viewer, they render as regular fenced code blocks — visible but clearly marked as code.

When the runtime lists actions — via /act, /act.<name> --help, the [actions] hint prepended on /open, or the “Actions on this page” section in /help — it shows only the call interface:

/act.search_city
--name <string> (required) — City name to search
--unit <string> (optional) — celsius|fahrenheit

The action method (GET, POST, CLI, etc.), the URL or command template, the body: template, headers, and response template directives are not shown. They are implementation — the runtime’s concern, not the caller’s. This keeps the help surface focused on “what to call, what to pass” and saves context tokens.

For inspection — security audit, debugging, curiosity — /source dumps the full .md file including all action blocks, body templates, headers, and response templates.


  1. Definition: fenced code block with act. info string prefix.
  2. First line: GET, POST, PUT, PATCH, DELETE, or CLI followed by endpoint/command.
  3. Headers: -H "Key: Value" on the first line, after URL. HTTP only. CLI templates preserve -H as part of the command.
  4. Parameters: indented, name: type (constraints) "description".
  5. Body template: body: directive (indented, multi-line). {field} substituted (JSON-string-aware). {field|modifier} for transforms. POST/PUT/PATCH only. If omitted, JSON.stringify(payload).
  6. Action IDs: [a-z][a-z0-9_-]*, unique within a document.
  7. Response template: act.id.response info string, optional.
  8. Response assignment: {var} = {expression} — no output.
  9. Response directives: save: (extract JSON path to buffer), decode: (transform buffer), to: (write buffer to file). Pipeline order.
  10. Response output: everything else — rendered as Markdown template with {Response.body.X}, {var}, and {field} substitution.
  11. Non-navigation: action invocation returns output text. The current document does NOT change. Sequential actions on the same page work without re-opening.
  12. Help visibility: /act and --help show verb + fields only. Method, URL, body, headers, response template are hidden. /source for full inspection.
  13. $variable in definitions: resolved from extraEnv → env-store → process.env (in that order).
  14. Invocation hints in inline code: conventional, not parsed.
  15. In CommonMark viewers, action blocks render as code blocks.