> ## Documentation Index
> Fetch the complete documentation index at: https://docs.davinci-app.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Actions

<img height="20" noZoom src="https://mintcdn.com/celedonsolutions/JD7z60pewriZ7tTc/images/objecticons/action.svg?fit=max&auto=format&n=JD7z60pewriZ7tTc&q=85&s=760fd6e7cebf0b27a09301d19f8c602a" data-path="images/objecticons/action.svg" />

## Description

Actions describe the behavior of a system using a subset textual syntax from SysML v2. Actions can be composed using nested levels to refine behavior in detail, with sequences defined using standard Python control flow and specialized action functions.

## Syntax for Action Modeling

Actions in Davinci use a Python-based syntax that aligns with SysML v2 action modeling principles. This approach provides:

* **Executable Behavior**: Actions are defined as executable Python code that can be simulated and tested
* **Hierarchical Composition**: Actions can call nested sub-actions to build complex behaviors from simple components
* **Standard Control Flow**: Use familiar Python constructs (if/else, for, while) for action sequencing

### Key Concepts

**Actions as Functions**: Each action is a function that can be called by parent actions or executed directly.

**Attribute Binding**: Attributes referenced in action sequences are global variables, enabling data flow between actions and physics simulations.

**Flow Modeling**: The `flow()` function explicitly models message passing and data routing between system components, critical for architectural definition.

## View Types

| View                                                  | Description                                              |
| :---------------------------------------------------- | :------------------------------------------------------- |
| [Activity](#activity-view)                            | Visually represent action flow and logic.                |
| [Sequence](#sequence-view)                            | Visualize interactions over time.                        |
| [Properties](/pages/user-guide/views/properties)      | Edit the object's properties, attributes, and metadata.  |
| [Table](/pages/user-guide/views/table)                | Display the object and its children in a tabular format. |
| [Tree](/pages/user-guide/views/tree)                  | View the hierarchical structure of the object.           |
| [Relationships](/pages/modeling/common/relationships) | Explore the network of connections to other objects.     |

## Properties Fields

<ParamField path="Inheritable" type="boolean">
  **Yes.** Actions can be used as bases or specializations through [object inheritance](/pages/modeling/common/inheritance).
</ParamField>

<ParamField path="Name" type="string">
  Name of the object.
</ParamField>

<ParamField path="Short Name" type="string">
  Short name of the object.
</ParamField>

<ParamField path="Documentation" type="string">
  Description of the object.
</ParamField>

<ParamField path="Sequence" type="code">
  Code that defines the action's behavior and flow. The sequence uses standard Python syntax with specialized functions and reference notation for modeling behaviors.
</ParamField>

<ParamField path="Attributes" type="object">
  <a href="/pages/modeling/objects/attributes" style={{ borderBottom: 'none' }}>
    <img height="20" noZoom src="https://mintcdn.com/celedonsolutions/JD7z60pewriZ7tTc/images/objecticons/attribute.svg?fit=max&auto=format&n=JD7z60pewriZ7tTc&q=85&s=ee78f4757a821d3bff63f0845a0f804c" data-path="images/objecticons/attribute.svg" />
  </a>

  A list of all Attribute objects owned by this action.

  Attribute Equations, Units and Type can be edited here, as well as recalculated and deleted entirely.

  [Read more about Attributes](/pages/modeling/objects/attributes)
</ParamField>

<ParamField path="Constraints" type="object">
  <a href="/pages/modeling/objects/constraints" style={{ borderBottom: 'none' }}>
    <img height="20" noZoom src="https://mintcdn.com/celedonsolutions/JD7z60pewriZ7tTc/images/objecticons/constraint.svg?fit=max&auto=format&n=JD7z60pewriZ7tTc&q=85&s=0ef10cabe6703b8e3bd5a86ecc22478c" data-path="images/objecticons/constraint.svg" />
  </a>

  A list of all Constraint objects owned by this action.

  Constraint Equations and Analysis Type can be editied here, as well as recalculated and deleted entirely.

  [Read more about Constraints](/pages/modeling/objects/constraints)
</ParamField>

<ParamField path="Relationships" type="connection">
  A list of all Relationships this object has with other model objects.

  [Read more about Relationships](/pages/modeling/common/relationships)
</ParamField>

## DSL Syntax

Davinci action sequences use a Python-like DSL. The runtime resolves model references before execution, but this documentation uses the friendlier `@'name'` notation for readability in examples.

<Info>
  In the underlying DSL implementation, model references are transformed into executable calls and bindings during preprocessing. The examples below keep the docs-friendly `@'name'` form, even though the runtime internally uses a lower-level resolved representation.
</Info>

### Model References

Actions, attributes, ports, and other modeled elements can be referenced using `@'name'`:

```python theme={null}
@'Initialize System'
@'Configure Parameters'
```

```python theme={null}
if @'status_code' == 200:
    @'output_value' = @'input_value' * 2
```

<Warning>Attributes are always single scalar values, not arrays or lists. Use multiple scalar attributes for vectors such as `@'pos_x'`, `@'pos_y'`, and `@'pos_z'`.</Warning>

### Attribute Runtime Behavior

Attributes act like execution-time scalar variables while an action is running.

When the sequence starts, referenced attributes are bound into the runtime so the action can read their current values:

```python theme={null}
if @'tank_pressure' > @'max_pressure':
    @'Open Relief Valve'()
```

Assignments update the runtime value of that attribute for the remainder of the execution and for any downstream logic that reads it during that run:

```python theme={null}
@'attempt_count' = @'attempt_count' + 1

if @'attempt_count' >= @'max_attempts':
    end(status="failed")
```

This is important:

* Reading `@'name'` pulls the current execution-time value for that attribute.
* Writing `@'name' = ...` updates the runtime value used by later steps in the same execution.
* These updates do **not** rewrite the modeled attribute definition itself.
* In other words, action code works with an execution context, not by editing the persistent model.

Use action inputs when a value should be explicitly passed in by the caller. Use attributes when the value is part of the modeled system state that the action should read or update during execution.

### Action Inputs

Actions can be defined in one of two ways:

### No-input actions

If an action does not need inputs, write the sequence directly. No `action(...)` declaration is needed.

```python theme={null}
@'Run Pre Checks'()
@'Load Configuration'()
@'Start Services'()
end()
```

Use this form when the action relies only on local logic, global model state, or previously bound attributes.

### Actions with inputs

If an action needs caller-provided values, declare them at the top with `action(...)`. The declared parameters become normal Python variables inside the action body.

```python theme={null}
action(speed, mode="nominal"):
    if mode == "nominal":
        @'Run Nominal Sequence'(value=speed)
    else:
        @'Run Degraded Sequence'()
    end()
```

```python theme={null}
action(config, threshold):
    result = @'Analyze Configuration'(config=config)
    if result.status == "ok" and result.score > threshold:
        end(status="passed")
    else:
        end(status="failed")
```

Rules for action definitions with inputs:

* `action(...)` must be the first non-comment line in the action sequence.
* If `action(...)` is present, the full executable body must be indented under it.
* Parameters are plain Python identifiers, not model references.
* Parameters without defaults are required at the call site.
* Parameters with defaults are optional at the call site.

### Calling Actions

Actions are called like functions. Parentheses are optional for no-argument calls and may be used with positional or keyword inputs.

```python theme={null}
# No-argument calls
@'Run Pre Checks'
@'Run Pre Checks'()

# Positional inputs
@'Configure System'(@'current_speed', "nominal")

# Keyword inputs
@'Configure System'(mode="nominal", speed=@'current_speed')

# Mixed inputs
@'Configure System'(@'current_speed', mode="nominal")
```

### Returning Outputs with `end()`

Actions return outputs by passing keyword arguments to `end(...)`. `end()` with no arguments is still valid when no outputs are needed.

```python theme={null}
# No outputs
end()

# One output
end(result=@'computed_value')

# Multiple outputs
end(velocity=@'computed_velocity', heading=@'computed_heading', status="ok")
```

### Capturing Outputs

When an action returns outputs, capture the result in a Python variable and access named outputs with dot notation.

```python theme={null}
outputs = @'Analyze Plan'(input=@'sensor_data')
@'analysis_result' = outputs.result
@'analysis_status' = outputs.status
```

Inline access is also valid when only one field is needed:

```python theme={null}
@'approval_status' = @'Review Test Plan'(plan=@'test_plan').status
```

### Control Flow

Standard Python control structures remain available:

```python theme={null}
if @'system_status' == "OK":
    @'Normal Startup'()
else:
    @'Recovery Mode'()
    end(status="recovery")
```

```python theme={null}
for i in range(int(@'retry_count')):
    @'Attempt Connection'()
    if @'connection_status' == "success":
        break
```

## Runtime Functions

### `fork([...])`

`fork()` executes multiple branches in parallel. A branch may be a single action call or a named `group(...)` block.

```python theme={null}
fork([@'Data Collection'(), @'System Monitoring'(), @'Log Events'()])
```

### `trigger(...)`

`trigger()` starts an action or state asynchronously and immediately continues the current flow.

```python theme={null}
trigger(@'Health Monitor'())
trigger(@'Send Alert'(severity="critical", message=@'alert_message'))
```

Use `trigger()` for fire-and-forget behavior. Do not use it when the current action needs the result before continuing.

### `end(...)`

`end()` exits the current action flow and may optionally return outputs.

```python theme={null}
if @'critical_error':
    @'Log Error'()
    end(status="failed")
```

### `stop()`

`stop()` immediately halts the current action hierarchy.

```python theme={null}
if @'emergency_condition':
    @'Emergency Shutdown'()
    stop()
```

### `checkpoint("name")` and `retry("name")`

Use checkpoints to label a recovery point and `retry()` to resume execution from that named location.

```python theme={null}
checkpoint("initialization")

@'Run Pre Checks'()
@'attempt_result' = @'System Init'(config=@'boot_config').status

if @'attempt_result' == "failed":
    if @'attempt_count' < @'max_attempts':
        @'attempt_count' = @'attempt_count' + 1
        retry("initialization")
    else:
        @'Enter Safe Mode'()
        end(status="safe_mode")
```

Guidelines:

* Checkpoint names must be unique within the action.
* `retry()` may only target a checkpoint defined in the same action.
* Guard `retry()` with a counter or condition to avoid infinite retry loops.

### `group("name"):` Blocks

Use `group(...)` to define a named sub-flow for a parallel branch. Groups must be declared before the `fork()` call that uses them.

```python theme={null}
group("branch_power"):
    @'Power Self Check'()
    if @'battery_level' < @'min_battery':
        @'Switch To Backup Power'()
    @'Confirm Power State'()

group("branch_comms"):
    for i in range(int(@'retry_limit')):
        @'Establish Link'()
        if @'link_established':
            break
    if not @'link_established':
        end(status="link_failed")

fork([branch_power, branch_comms, @'Start Logging'()])
```

## Message Flow Modeling

Use `flow()` to explicitly model data and message routing between ports or entities:

```python theme={null}
flow(@'command_port', @'actuator_port', "command", [@'Control Signal'])

if @'mode' == "autonomous":
    flow(@'sensor_port', @'ai_processor_port', "sensor_data", [@'Image Data', @'Telemetry'])
    @'AI Decision Making'()
    flow(@'ai_processor_port', @'command_port', "decision", [@'Command'])
else:
    flow(@'sensor_port', @'operator_display_port', "sensor_data", [@'Image Data'])
    flow(@'operator_input_port', @'command_port', "manual_command", [@'Command'])
```

## Code Object References

Code objects may be called and imported inside action sequences:

```python theme={null}
@'calculated_torque' = @'PD Control Algorithm'.compute_torque(@'current_attitude', @'target_attitude')

import @'Utilities Code'
result = @'Utilities Code'.helper_function(@'input_data')
```

## Complete Example

```python theme={null}
action(config, max_attempts=3):
    checkpoint("boot_start")

    trigger(@'Health Monitor'())

    init_outputs = @'System Initialization'(config=config, timeout=30)
    @'init_status' = init_outputs.status

    if @'init_status' == "ready":
        group("branch_power"):
            @'Power Self Check'()
            if @'battery_level' < @'min_battery':
                @'Switch To Backup Power'()
            @'Confirm Power State'()

        group("branch_comms"):
            plan = @'Build Comms Test Plan'()
            approval = @'Review Comms Plan'(plan.result)
            @'comms_approval' = approval.status
            if @'comms_approval' == "approved":
                @'Establish Link'()
            else:
                end(status="comms_rejected")

        fork([branch_power, branch_comms, @'Start Logging'()])
        @'Begin Primary Operations'()

    elif @'init_status' == "degraded":
        if @'attempt_count' < max_attempts:
            @'attempt_count' = @'attempt_count' + 1
            retry("boot_start")
        else:
            @'Enter Safe Mode'()
            end(status="safe_mode")

    else:
        stop()

    end(status="nominal")
```

## Best Practices

### Action Composition

* **Single Responsibility**: Give each action a clear purpose.
* **Hierarchical Design**: Decompose complex behavior into smaller reusable actions.
* **Consistent Outputs**: Prefer consistent output keys across branches when returning data from `end(...)`.

### Sequence Definition

* **Use Inputs Deliberately**: Prefer `action(...)` parameters for local action inputs instead of relying only on global attributes.
* **Guard Recovery Paths**: Protect `retry()` with explicit retry limits or exit conditions.
* **Keep Groups Focused**: Use `group(...)` only to express meaningful parallel branches.
* **End Intentionally**: Use `end()` when you need to terminate early or return outputs; otherwise allow the sequence to reach its natural end.

## Technical Implementation

### Parse-Time Resolution

When an action sequence is executed, the system performs several preprocessing steps before runtime:

1. **Reference Resolution**: Model references such as `@'Initialize System'` are resolved into executable calls and bindings.
2. **Action Hoisting**: `action(...)` declarations are transformed into callable action entry points with injected parameters.
3. **Group Hoisting**: `group("name"):` blocks are rewritten into callable branch functions for use by `fork()`.
4. **Runtime Primitive Wiring**: `trigger()`, `checkpoint()`, and `retry()` are connected to runtime execution semantics.
5. **Code Import Resolution**: Code-object references are transformed into module imports and callable functions as needed.
