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

# Script Quickstart

> In this quick start guide, we will write our first script in Python. getOperate provides a Python 3.11 environment.

## Python Script

Scripts are the basic building blocks in getOperate. They can be run and scheduled as standalone, chained together to create Flows or displayed with a personalized User Interface as Apps.

<CardGroup cols={2}>
  <Card title="Script Editor" href="/developer/manual/script">
    All the details on scripts.
  </Card>

  <Card title="Triggering Scripts" href="/introduction/quickstart/triggering-scripts">
    Trigger flows on-demand, by schedule or on external events.
  </Card>
</CardGroup>

Scripts consist of 2 parts:

* [Code](#code): for Python scripts, it must have at least a main function.
* [Settings](#settings): settings & metadata about the Script such as its path, summary, description, jsonschema of its inputs (inferred from its signature).

When stored in a code repository, these 2 parts are stored separately at `<path>.ts` and `<path>.script.yaml`

This is a simple example of a script built in Python with getOperate:

```python theme={null}
#import getOperate
import nltk
from nltk.sentiment import SentimentIntensityAnalyzer
nltk.download("vader_lexicon")

def main(text: str = "Wow, NLTK is really powerful!"):
    return SentimentIntensityAnalyzer().polarity_scores(text)
```

In this quick start guide, we'll create a script that greets the operator running it.

From the Home page, click `+Script`. This will take you to the first step of script creation: Metadata.

### Settings

As part of the settings menu, each script has metadata associated with it, enabling it to be defined and configured in depth.

* **Path** is the Script's unique identifier that consist of the script's owner, and the script's name. The owner can be either a user, or a group (folder).
* **Summary** (optional) is a short, human-readable summary of the Script. It will be displayed as a title across getOperate. If omitted, the UI will use the `path` by default.
* **Language** of the script.
* **Description** is where you can give instructions through the auto-generated UI to users on how to run your Script. It supports markdown.
* **Script kind**: Action (by default), Trigger, Approval or Error Handler. This acts as a tag to filter appropriate scripts from the flow editor.

This menu also has additional settings, such as:

* **Concurrency limits** enable defining concurrency limits for scripts and inline scripts within flows to prevent exceeding the API Limit of the targeted API.
* **Worker group tag** to assign scripts to specific worker groups (such as nodes with GPU accelaration).
* **Cache** to cache the results for each possible inputs for a given time.
* **Dedicated Workers** to run the script on, to run the script at native speed. Only available on enterprise edition and for the Bun language.

<Card title="Settings" href="#">
  Each script has metadata & settings associated with it, enabling it to be defined and configured in depth.
</Card>

Now click on the code editor on the left side, and let's build our Hello World!

### Code

We provides an online editor to work on your Scripts. The left-side is the editor itself. The right-side previews the UI that getOperate will generate from the Script's signature - this will be visible to the users of the Script. You can preview that UI, provide input values, and test your script there.

<CardGroup cols={2}>
  <Card title="Code Editor" href="/developer/manual/code">
    The code editor is getOperate's integrated development environment.
  </Card>

  <Card title="Auto-generated UIs" href="#">
    We creates auto-generated user interfaces for scripts and flows based on their parameters.
  </Card>
</CardGroup>

As we picked `python` for this example, We provided some python boilerplate. Let's take a look:

```python theme={null}
import os
import getOperate

# You can import any PyPi package. 

# you can use typed resources by doing a type alias to dict
#postgresql = dict

def main(
    no_default: str,
    #db: postgresql,
    name="Nicolas Bourbaki",
    age=42,
    obj: dict = {"even": "dicts"},
    l: list = ["or", "lists!"],
    file_: bytes = bytes(0),
):

    print(f"Hello World and a warm welcome especially to {name}")
    print("and its acolytes..", age, obj, l, len(file_))

    # retrieve variables, resources, states using the getOperate client
    try:
        secret = getOperate.get_variable("f/examples/secret")
    except:
        secret = "No secret yet at f/examples/secret !"
    print(f"The variable at `f/examples/secret`: {secret}")

    # Get last state of this script execution by the same trigger/user
    last_state = getOperate.get_state()
    new_state = {"foo": 42} if last_state is None else last_state
    new_state["foo"] += 1
    getOperate.set_state(new_state)

    # fetch context variables
    user = os.environ.get("GO_USERNAME")

    # return value is converted to JSON
    return {"splitted": name.split(), "user": user, "state": new_state}
```

Scripts need to have a `main` function that will be the script's entrypoint. There are a few important things to note about the `main`.

* The main arguments are used for generating
  * the input spec of the Script
  * the frontend that you see when running the Script as a standalone app.
* Type annotations are used to generate the UI form, and help pre-validate inputs. While not mandatory, they are highly recommended. You can customize the UI in later steps (but not change the input type!).

<Card title="JSON Schema and Parsing" href="#">
  JSON Schemas are used for defining the input specification for scripts and flows, and specifying resource types.
</Card>

The last import line imports the client, which is needed for example to access variables or resources.

<CardGroup cols={2}>
  <Card title="Dependency Management & Imports" href="#">
    getOperate's strength lies in its ability to run scripts without having to deal with separate dependency files.
  </Card>

  <Card title="Python Client" href="#">
    The Python client library for getOperate provides a convenient way to interact with the getOperate platform's API from within your script jobs.
  </Card>
</CardGroup>

Back to our Hello World. We can clean up unused import statements, change the
main to take in the user's name. Let's also return the `name`, maybe we can use
this later if we use this Script within a [flow](/developer/cli/flows) or [app](/developer/cli/apps) and need to pass its result on.

```py theme={null}
def main(name: str):
  print("Hello world. Oh, it's you {}? Greetings!".format(name))
  return name
```

### Instant Preview & Testing

Look at the UI preview on the right: it was updated to match the input
signature. Run a test (`Ctrl` + `Enter`) to verify everything works.

You can change how the UI behaves by changing the main signature. For example,
if you add a default for the `name` argument, the UI won't consider this field
as required anymore.

```py theme={null}
main(name: str = "you")
```

<Card title="Instant Preview & Testing" href="/workflows/deploy/instant-preview-testing">
  On top of its integrated editors, We allows users to see and test what they are building directly from the editor, even before deployment.
</Card>

Now let's go to the last step: the "Generated UI" settings.

### Customize UI

From the Settings menu, the "Generated UI" tab lets you customize the script's arguments.

The UI is generated from the Script's main function signature, but you can add additional constraints here. For example, we could use the `Customize property`: add a regex by clicking on `Pattern` to make sure users are providing a name with only alphanumeric characters: `^[A-Za-z0-9]+$`. Let's still allow numbers in case you are some tech billionaire's kid.

<CardGroup cols={2}>
  <Card title="Script Kinds" href="#">
    You can attach additional functionalities to Scripts by specializing them into specific Script kinds.
  </Card>

  <Card title="Customize UI" href="#">
    Some arguments' types can be given advanced settings that will affect the inputs' auto-generated UI and JSON Schema.
  </Card>
</CardGroup>

### Run!

We're done! Now let's look at what users of the script will do. Click on the [Deploy](/workflows/deploy/variables-secrets) button
to load the script. You'll see the user input form we defined earlier.

Note that Scripts are versioned in getOperate, and
each script version is uniquely [identified by a hash](#)

Fill in the input field, then hit "Run". You should see a run view, as well as
your logs. All script runs are also available in the [Runs](#) menu on
the left.

You can also chose to [run the script from the CLI](/developer/cli/installation) with the pre-made Command-Line Interface call.

<Card title="Triggering Scripts" href="/introduction/quickstart/triggering-scripts">
  Trigger flows on-demand, by schedule or on external events.
</Card>

### What's next?

This script is a minimal working example, but there's a few more steps that can be useful in a real-world use case:

* Pass [variables and secrets](/workflows/deploy/variables-secrets)
  to a script.
* Connect to [resources](#).
* [Trigger that script](/introduction/quickstart/triggering-scripts) in many ways.
* Compose scripts in [Flows](/developer/cli/flows) or [Apps](/developer/cli/apps).
* You can [share your scripts](#) with the community on [getOperate Hub](#). Once
  submitted, they will be verified by moderators before becoming available to
  everyone right within getOperate.

Scripts are immutable and there is an hash for each deployment of a given script. Scripts are never overwritten and referring to a script by path is referring to the latest deployed hash at that path.

<Card title="Versioning" href="/developer/version-control#versioning">
  Scripts, when deployed, can have a parent script identified by its hash.
</Card>

For each script, a UI is autogenerated from the jsonchema inferred from the script signature, and can be customized further as standalone or embedded into rich UIs using the [App builder](#).

<CardGroup cols={2}>
  <Card title="Auto-generated UIs" href="#">
    We creates auto-generated user interfaces for scripts and flows based on their parameters.
  </Card>

  <Card title="Customize UI" href="#">
    Some arguments' types can be given advanced settings that will affect the inputs' auto-generated UI and JSON Schema.
  </Card>
</CardGroup>

In addition to the UI, sync and async [webhooks](#) are generated for each deployment.

<Card title="Webhooks" href="#">
  Trigger scripts and flows from webhooks.
</Card>
