Scripts

Scripts are small programs you write once and run on your desktop. Use them when you need to do something to your data that an automation or form can't — converting a spreadsheet, generating reports, cleaning up records, calling an HTTP API, packaging files.

Scripts run on your computer, not on Nocarta's servers. Your inputs, outputs, and secrets never leave your machine during execution.

When should I use a script?

You want to…Use
Automate a website (click, fill, navigate)Automation (Automation)
Digitize a paper document or photoQuick Document Capture
Transform CSV/Excel/PDF/JSON filesScript
Generate a report from your dataScript
Call an external API and write results to a fileScript

Requirements

The Nocarta Desktop App is required to run scripts. Editing a script in your browser works anywhere, but the actual execution happens on your computer.

Download Nocarta Desktop


Creating a script

Open Scripts → New Script and fill in:

  • Name — what you'll see in the list. Pick something memorable.
  • Description — a short note to your future self about what this script does.
  • Kind — see the next section. Pick Node if you're starting from scratch.
  • Run command — for Shell scripts, the command that runs your source file (e.g. python3 main.py). For Node scripts this is cosmetic — the desktop app runs your code on its built-in Node runtime regardless, so it's not shown on a Node script's page.
  • Source filename — the name your source code gets saved as on disk during a run. main.py / convert.sh / extract.rb for Shell. For Node it's fixed to main.js and, like the run command, is cosmetic.
  • Source code — the actual program. See the two examples below.
  • Persist stdout/stderr to backend — off by default. When on, the text your script prints is saved to Nocarta and visible in the Runs tab. When off, it's only visible live during the run.

The two kinds

You choose how your script will be executed on the desktop:

Node

Recommended for new scripts. Runs on the Node.js runtime that ships with the desktop app — nothing extra to install. Your computer doesn't even need Node installed.

Your source code must export an async function:

module.exports = async function ({ inputDir, outputDir, env, log }) {
  const fs = require('fs');
  const path = require('path');

  // Read inputs from inputDir, write outputs to outputDir.
  const data = fs.readFileSync(path.join(inputDir, 'input.csv'), 'utf8');
  fs.writeFileSync(path.join(outputDir, 'result.txt'), data.toUpperCase());

  log('Done!');
};

What you get in the function arguments:

  • inputDir — folder containing any input files you attached to this run.
  • outputDir — anything you write into this folder is collected and uploaded back to Nocarta when the script finishes.
  • env — environment variables, including any secrets you've bound (see Secrets).
  • log(message) — prints to the script's output stream.

Standard Node modules (fs, path, crypto, http, https, url, util, …) are always available via require(). For extra npm packages, see Allow npm packages.

Shell

Use this when you need a language other than JavaScript — Python, Ruby, bash, Go, anything. Spawns a process using your system shell.

Important: your computer must have the runtime installed and on PATH. If you write run command: python3 main.py, Python 3 must be available when you click Run.

Your source code is whatever the run command expects. Example for python3 main.py:

import sys, os, csv

input_path  = os.path.join(os.environ.get('PWD', '.'), 'input', 'input.csv')
output_path = os.path.join(os.environ.get('PWD', '.'), 'output', 'result.txt')

with open(input_path) as f:
    rows = list(csv.reader(f))

with open(output_path, 'w') as f:
    f.write(f"{len(rows)} rows processed\n")

print("Done!", file=sys.stderr)

Same input/output folder convention as Node — your script reads from input/ and writes to output/ inside its working directory.


Parameters — asking for input at run time

Instead of hardcoding values (a file to process, a template name, a server URL) at the top of your source, declare parameters. Each one becomes a field in a small dialog that pops up every time you click Run, so the same script can target different inputs without ever editing the code.

Add them in the script's Parameters editor. Each parameter has a name (UPPER_SNAKE_CASE — it becomes an environment variable), a type, a label, optional help text, an optional default, and a required flag.

Types

TypeWhat the user sees in the dialogHow you read it in the script
textsingle-line text boxenv.NAME
multilinemulti-line text areaenv.NAME
numbernumber inputenv.NAME (as a string)
datedate input (YYYY-MM-DD)env.NAME
emailemail inputenv.NAME
regexptext, validated as a regular expressionenv.NAME
selectdropdown of the options you defineenv.NAME
filefile pickerinputDir/<NAME> — see below

Every type except file arrives as an environment variable. In a Node script, read it from env.MY_PARAM (or process.env.MY_PARAM); in a Shell script, from $MY_PARAM. A blank optional field falls back to its default; a blank required field stops the run with a clear message.

File parameters

A file parameter shows a file picker in the run dialog — this is the dialog you see when a script needs you to choose, say, a spreadsheet. The file you pick is not an environment variable. It's downloaded into your working folder as inputDir/<parameter name>. So a file parameter named XLSX_FILE is read like this:

module.exports = async function ({ inputDir }) {
  const fs = require('fs');
  const path = require('path');
  const buf = fs.readFileSync(path.join(inputDir, 'XLSX_FILE'));
  // …
};

Parameter names can't start with NOCARTA_ or ELECTRON_ (reserved), and can't clash with the env-var name of a bound secret — parameters and secrets share the same environment.


Binding secrets

If your script needs an API key, password, or database URL, don't paste it into the source. Instead:

  1. Store the value in your Vault (e.g. a Secret named "Stripe Live Key").
  2. Open the script's Secrets tab and bind that Vault entry to an env var name, e.g. STRIPE_KEY.
  3. Access it from your script via process.env.STRIPE_KEY (Node) or os.environ['STRIPE_KEY'] (Shell).

Only the secrets you've explicitly bound are visible to the script. Everything else in your Vault stays out of reach.

The value is automatically blanked from any output the script prints — if your script accidentally log(STRIPE_KEY), what gets stored on the server is [REDACTED:STRIPE_KEY], never the real value.


Running a script

From the script's page, click Run. The desktop app:

  1. Downloads your source code and any input files into a working folder on your computer.
  2. Executes the script (Node or Shell).
  3. Captures everything written to output/ and uploads it back to Nocarta.
  4. Marks the run completed (exit 0) or failed (any non-zero exit).

Output files appear under the Runs tab with a Download link. If you turned on "Persist logs", the printed output is there too.

Cancelling

Long-running script? Click Cancel on the live run panel. The desktop app sends the script a stop signal, then force-kills it 5 seconds later if it hasn't shut down on its own.


Allow npm packages — please read carefully

By default, a Node script can use only Node's built-in modules. If you need something from the npm registry (e.g. axios, exceljs, uuid), you can enable the Allow this script to install npm packages switch on the script form.

This switch is off by default for a reason. Before turning it on, you must read and acknowledge the danger modal that appears. Here's what's in it:

What happens. When this script runs, the desktop app downloads the npm packages you declare and saves them in a cache folder on your computer. They're then loaded by your script via require().

Why this is risky.

  • npm packages are arbitrary code written by anyone. A malicious package — or a hijacked version of a package you trust — can read your files, exfiltrate data, or abuse your computer's network.
  • Nocarta blocks the most common attack vector (package "install scripts" that auto-run at install time), but once your script loads a package, the package can do anything your script can do.
  • Only enable this for scripts where you've checked every package in your list.

No system installation needed. The desktop app ships with everything required to download and install packages — your computer doesn't need Node.js, npm, or any other developer tool installed.

You'll be asked every time. Even after enabling the switch, every time you click Run on this script, you'll see a confirmation dialog. There is no "remember my choice."

Once enabled, the form shows a package.json field. Put your dependencies there as a JSON object — exact versions only, no ranges:

{
  "dependencies": {
    "uuid": "9.0.1",
    "axios": "1.6.2"
  }
}

In your source code, require() them the normal way:

module.exports = async function ({ outputDir }) {
  const { v4: uuidv4 } = require('uuid');
  const axios = require('axios');
  // …
};

The first run with a new dependency list takes a moment (downloading packages). Subsequent runs are fast — the packages are reused from cache.


Common questions

Where are my output files saved?

After the run finishes, they appear in the Runs tab of your script, with a Download link. They're stored in Nocarta and tied to that specific run.

Why is my Shell script failing with "command not found"?

Shell scripts use the runtimes installed on your computer. If you wrote run command: python3 main.py and Python 3 isn't on your PATH, the run fails. Either install it, switch to a runtime you have, or use a Node script (which has no system requirements).

I changed my source code — is the old version gone?

No. Every save creates a new version. Past runs always reference the exact version they used. You can go back to any older version if needed.

Can I see what my script prints?

During a run, live output is visible on the script's page. To keep that output around afterwards, turn on Persist stdout/stderr to backend. Off by default to avoid storing sensitive data accidentally.

Can I run a script on a schedule?

Not yet — scripts are triggered manually from the desktop app. Scheduling is on the roadmap.

Need More Help?

Ask AI Assistant