Actions
Actions
Section titled “Actions”Actions define executable operations within a document. They are
written as fenced code blocks with an act. info string prefix.
Definition syntax
Section titled “Definition syntax”An action is defined in a fenced code block whose info string
starts with act.:
```act.action_idTYPE 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 ID rules
Section titled “Action ID rules”Action IDs MUST follow these rules:
| Rule | Valid | Invalid |
|---|---|---|
| Lowercase letters | search | Search |
| Numbers allowed | get_v2 | — |
| Underscores allowed | search_city | — |
| Hyphens allowed | search-city | — |
| Must start with a letter | deploy | 2deploy |
Pattern: [a-z][a-z0-9_-]*
Action IDs MUST be unique within a document.
Action types
Section titled “Action types”The first line of the code block declares the type and topic.
GET https://api.example.com/searchHTTP GET request. Parameters are sent as query string.
POST https://api.example.com/submitHTTP 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
Section titled “DELETE”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.
Parameter definitions
Section titled “Parameter definitions”Each parameter is defined on its own line, indented with spaces:
name: type (constraints) "description"Fields
Section titled “Fields”| Field | Required | Description |
|---|---|---|
name | Yes | Parameter name |
type | Yes | Data type |
constraints | No | Parenthesized constraints |
description | No | Quoted description text |
| Type | Description |
|---|---|
string | Text value |
number | Numeric value (integer or float) |
boolean | True or false |
path | File path |
Constraints
Section titled “Constraints”Constraints appear in parentheses, comma-separated:
| Constraint | Meaning |
|---|---|
required | Parameter must be provided |
optional | Parameter may be omitted (default) |
| value hints | Allowed values, e.g. celsius|fahrenheit |
max:N | Maximum value or length |
min:N | Minimum value or length |
Examples
Section titled “Examples” 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"Complete definition examples
Section titled “Complete definition examples”GET action
Section titled “GET action”```act.search_cityGET https://api.weather.com/search name: string (required) "City name to search" unit: string (optional) "celsius|fahrenheit"```POST action
Section titled “POST action”```act.create_alertPOST https://api.weather.com/alerts city: string (required) "Topic city" condition: string (required) "rain|snow|temp" threshold: number (optional) "Trigger value"```PUT action
Section titled “PUT action”```act.update_alertPUT https://api.weather.com/alerts/{alert_id} alert_id: string (required) "Alert ID" condition: string (required) "New condition"```PATCH action
Section titled “PATCH action”```act.patch_settingsPATCH https://api.weather.com/users/{user_id}/settings user_id: string (required) "User ID" unit: string (optional) "celsius|fahrenheit"```DELETE action
Section titled “DELETE action”```act.delete_alertDELETE https://api.weather.com/alerts/{alert_id} alert_id: string (required) "Alert ID"```CLI action
Section titled “CLI action”```act.deployCLI kubectl apply -f {manifest} manifest: path (required) "Kubernetes manifest file"```Headers
Section titled “Headers”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"Syntax
Section titled “Syntax”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
-Hflags $variable— persistent variable (configuration, credentials){variable}— session variable (runtime data)
Examples
Section titled “Examples”```act.inboxGET https://gmail.googleapis.com/v1/users/me/messages -H "Authorization: Bearer {access_token}" maxResults: number (optional) q: string (optional) "Search query"``````act.create_issuePOST 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)```- Headers appear on the first line only, after the URL.
- Each header is a separate
-H "Key: Value"flag. - Variable substitution (
{var}and$var) applies to header values. - No default headers are injected for actions — only declared headers are sent.
Body template
Section titled “Body template”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.
Syntax
Section titled “Syntax”```act.generatePOST 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 thebody: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}.
Field modifiers
Section titled “Field modifiers”| Modifier | Effect |
|---|---|
{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.
When body: is omitted
Section titled “When body: is omitted”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.
Invocation hint
Section titled “Invocation hint”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.
Response template
Section titled “Response template”An action MAY have a companion response template defined in a separate code block:
```act.action_id.responsetemplate content```The info string is act. + action ID + .response.
Template lines
Section titled “Template lines”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.dataThe 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: base64Currently 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}°COutput 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.
Save/decode/to pipeline
Section titled “Save/decode/to pipeline”The three directives form a pipeline for extracting binary data from JSON API responses:
save:reads a JSON path → buffer is a string (the raw value)decode: base64converts the buffer → buffer is now bytesto: {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.datadecode: base64to: {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.
Complete example (text template)
Section titled “Complete example (text template)”```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 reference syntax
Section titled “Response reference syntax”Response data is accessed using dot-and-bracket notation:
| Reference | Meaning |
|---|---|
{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.
Execution behavior
Section titled “Execution behavior”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.
Variable references in actions
Section titled “Variable references in actions”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.
Visibility
Section titled “Visibility”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.
Help and action listings
Section titled “Help and action listings”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|fahrenheitThe 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.
Rules summary
Section titled “Rules summary”- Definition: fenced code block with
act.info string prefix. - First line:
GET,POST,PUT,PATCH,DELETE, orCLIfollowed by endpoint/command. - Headers:
-H "Key: Value"on the first line, after URL. HTTP only. CLI templates preserve-Has part of the command. - Parameters: indented,
name: type (constraints) "description". - 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). - Action IDs:
[a-z][a-z0-9_-]*, unique within a document. - Response template:
act.id.responseinfo string, optional. - Response assignment:
{var} = {expression}— no output. - Response directives:
save:(extract JSON path to buffer),decode:(transform buffer),to:(write buffer to file). Pipeline order. - Response output: everything else — rendered as Markdown template with
{Response.body.X},{var}, and{field}substitution. - Non-navigation: action invocation returns output text. The current document does NOT change. Sequential actions on the same page work without re-opening.
- Help visibility:
/actand--helpshow verb + fields only. Method, URL, body, headers, response template are hidden./sourcefor full inspection. $variablein definitions: resolved from extraEnv → env-store → process.env (in that order).- Invocation hints in inline code: conventional, not parsed.
- In CommonMark viewers, action blocks render as code blocks.