Netridium Prompt Language

LogicScript Prompt Language (LSPL)

For IT, administrators, and consultants who want to build powerful, repeatable AI tools — AI Tools — that their clients and end users run with one click in Netridium.

This guide is the reference for the LogicScript Prompt Language (LSPL). It assumes no programming background: if you can describe a process in clear, structured steps, you can write an LSPL tool.

In one line: you write the procedure; the AI runs it — step by step, using your connected systems — and returns a finished result. The script is the prompt. The AI is the runtime.


1. What LSPL is

LSPL is a structured language for describing what a tool should do, in plain, readable steps. You write the procedure — the checks, the decisions, the order of operations, the shape of the output — and the AI carries it out: reasoning where you ask it to, branching on its conclusions, reading from your connected systems, and assembling the result.

It sits between Netridium's other two ways to build a tool:

  • A Prompt is the fastest path — you describe the outcome in a sentence or two

    and let the AI work out the whole approach.

  • A Script (Python) is fully deterministic — you write exact code.
  • LSPL is the middle ground: you make the process explicit and repeatable,

    while the AI still supplies the judgement at each step. Two people read the same script the same way, and it runs the same across many inputs.

See LOGICSCRIPT_TYPES.md for the full three-type comparison.


2. The mental model

When a user runs your LSPL tool, Netridium:

  1. Collects any pre-run inputs you defined (a short form) and passes them to the

    script as its arguments.

  2. Hands the AI your AI Tool and has it carry out each step.
  3. Lets the AI read from your connectors as the script directs (read-only).
  4. Captures what the script RETURNs (and any EMIT/LOG lines) and renders it as

    the deliverable — an Excel workbook, PDF, HTML page, chart, text, or JSON.

A few consequences worth internalizing:

  • The AI fills in the reasoning; you fix the process. The branches, validations,

    output shape, and order of steps are yours. The wording and judgement inside each AI.call will vary run to run — that's the point. Pin down anything that must be exact.

  • Runs are read-only. An LSPL tool can read and analyze your systems, but it

    cannot change data or send real messages. To write data or send email, use a Python Script (the only write-capable type). See §9.

  • A run produces one result. Like every AI Tool, it's fire-and-finish: the

    user clicks Run and gets a result back. There is no mid-run pause for more input — collect everything you need up front with Inputs (§7).

  • At least one connector is required. An LSPL tool is linked to one or more

    connectors (the systems it may read).


3. Anatomy of an AI Tool

An AI Tool is usually a single FUNC run(...) with an optional INPUTS block, a VALIDATE block, a DO block of steps, and a RETURN:

INPUTS
  period:   select [last_month, this_month, last_quarter]
  customer: text optional

FUNC run(period, customer)
  --- Produce an accounts-receivable aging summary for the chosen period. ---

  VALIDATE
    period not empty

  DO
    -- 1. Pull the data
    invoices = mcp("xero").call("list_invoices", { status: "AUTHORISED" })

    -- 2. Reason over it
    aging = AI.call(
      "Bucket these invoices into Current, 1–30, 31–60, 61–90, and 90+ days
       overdue. Total each bucket and compute the percentage of the balance."
    )

    LOG "Bucketed {invoices.length} invoices for {period}"

  RETURN aging

That's the whole shape: declare inputs → validate → do the steps → return a result. Everything else in this guide is the vocabulary that goes inside.


4. Language reference

These are the constructs the language understands. Indentation is 2 spaces per level — there are no braces or end keywords.

Comments

-- inline comment to the end of the line

--- A block comment / docstring.
    Use it under FUNC to state the goal in plain English. ---

A ----delimited block right under FUNC is the best place to state the tool's purpose; the AI reads it as the mission.

Variables & assignment

Assign the result of a step to a name and reuse it later:

invoices = mcp("xero").call("list_invoices", {})
overdue  = AI.call("From the invoices above, keep only those past their due date.")
count    = overdue.length

Variables are inferred — you don't declare types. Dotted access (ticket.subject, invoice.amount) reads a field.

String interpolation

Insert a value into a string with single braces { }:

LOG "Found {count} overdue invoices for {customer}"

INPUTS — pre-run parameters

Declare the values a user supplies before the run. (In Netridium, the actual form is built in the AI Tool editor's Inputs section — see §7 — and mirroring it here keeps the script readable and tells the AI what arguments to expect.)

INPUTS
  accounts:  select FROM connector("xero").accounts   -- dynamic options
  recipient: user                                      -- pick a workspace user
  template:  select [welcome, reminder, overdue]       -- static options
  asOf:      date
  note:      text optional

Field kinds: text, number, bool, date, select [a, b, c] (static), select FROM connector(...) (dynamic options from a connected system), and user (a workspace user). Add optional to make a field non-required.

VALIDATE — preconditions

Checked before any work happens; the first failure stops the run and is reported instead of continuing. One condition per line; plain English is fine:

VALIDATE
  period not empty
  asOf is a valid date
  accounts has at least one item   MESSAGE "Pick at least one account"

Add MESSAGE "…" to give the user a clear error.

DO — the sequence of steps

The body. Steps run top to bottom: assignments, connector reads, AI.calls, conditionals, loops, LOG, and EMIT.

AI.call("…") — reason or decide here

The heart of an LSPL tool. Wherever judgement is needed, hand the AI a focused instruction; it reasons over the data in scope and returns the result:

classification = AI.call(
  "Read the ticket and return: priority (low/medium/high/urgent),
   category (billing/shipping/account/technical/general), and whether you can
   resolve it yourself (yes/no). Respond as: priority / category / yes-or-no"
)

Be specific. The tighter the instruction (what to produce, what format, what edge cases), the more consistent the output. Vague AI.calls are where runs drift.

IF / ELSE IF / ELSE — branching

Branch on the AI's own conclusions. Conditions can be structured or plain English:

IF classification.canResolve IS yes AND ticket.attempts < 2
  -- attempt resolution
ELSE IF classification.priority IS urgent
  -- fast-track
ELSE
  -- escalate

FOR EACH … IN … — iteration

Repeat steps over a collection:

FOR EACH invoice IN overdue
  reminder = AI.call("Draft a one-line overdue note for invoice {invoice.number}.")
  EMIT Reminder
    invoice: {invoice.number}
    text:    {reminder}

Reading from connectors — mcp(...) and QUERY

Direct the AI to pull data from a connected system. Two readable forms:

-- Call a connector's tool directly:
invoices = mcp("xero").call("list_invoices", { status: "AUTHORISED" })

-- Or describe the retrieval (the AI maps it to the right tool):
QUERY overdueInvoices
  FROM    Xero.Invoices
  WHERE   status = "AUTHORISED" AND dueDate < today
  ORDER BY dueDate ASC
  LIMIT   500

Use the connector name exactly as it appears on the Connectors page. All connector access in an LSPL tool is read-only (see §9). For the tools each connector exposes, see CONNECTOR_SETUP_FOR_ADMINS.md.

LOG — narrate the run

A note about what just happened. Useful for traceability; the AI folds these into the result/run log where helpful:

LOG "Reconciled {matched} of {total} transactions; {unmatched} unmatched"

EMIT EventName — structured output

Emit a labelled, structured record. Emitted events are captured as part of the result — ideal for line items, flags, or a status payload:

EMIT ReconciliationResult
  status:   {status}
  matched:  {matched}
  unmatched:{unmatched}
  comments: {comments}

(The compact form EMIT EventName WITH { matched, unmatched } also works.)

RETURN — the final result

Ends the procedure and designates the value the tool produces. What you RETURN (together with any EMITs) becomes the deliverable, rendered into one of the output formats in §8:

RETURN aging

5. Actions: SEND, ALERT, NOTIFY (read-only)

The language includes verbs for actingSEND a message, ALERT a team, NOTIFY a user. In Netridium these are read-only: the AI drafts and clearly labels them in the result, but nothing is actually sent and no data is changed.

SEND TO {ticket.customerEmail}
  Subject: Re: {ticket.subject}
  Body: {response}

ALERT support-team
  Ticket {ticket.id} needs human attention — {classification.priority} priority.

In the result you'll see these as a drafted email and a flagged alert — perfect for review-and-send workflows where a human approves the output. To actually send email or write data, build a Python Script (the write-capable AI Tool type), which can call a connector's write tools under explicit, audited permission. See §9.


6. Conditions & expressions

Conditions (in VALIDATE, IF, WHERE) can be written structurally or in plain English — whichever is clearer:

  • Comparisons: amount > 1000, dueDate < today, attempts < 2
  • Equality / membership: status IS resolved, category IN [billing, shipping]
  • Text: response does not contain "CANNOT RESOLVE", email matches email pattern
  • Boolean logic: AND, OR, NOT
  • Presence: subject not empty, accounts has at least one item
  • Plain English: the invoice looks like a duplicate — valid anywhere a structured

    expression is awkward; the AI evaluates it.

Lean on plain English for judgement and structured form for facts — it keeps the intent obvious to both the AI and the next person who reads your script.


7. Inputs — the run form

Pre-run inputs turn a one-off script into a reusable, self-service tool. In Netridium you define them in the AI Tool editor's Inputs section; Netridium renders a short form, validates the values, and passes them to your script as run(...)'s arguments. Reference them by name and interpolate with { }.

Field kind Renders as Example
text A text box note: text optional
number A numeric input threshold: number
bool A checkbox includeDrafts: bool
date A date picker asOf: date
select [a, b, c] A dropdown of fixed options period: select [last_month, this_month]
select FROM connector(...) A dropdown filled from a connected system account: select FROM connector("xero").accounts
user A picker of workspace users owner: user

Mirror these in an INPUTS block at the top of your script so the procedure reads clearly. Full detail: PROMPT_INPUTS.md.


8. Output formats

Whatever your script RETURNs is rendered into the format that best fits the task. Aim your result at one of these — say so in your closing AI.call/RETURN if it matters:

Format Use it for
Excel Tabular data — the common case (rows × columns, one or more sheets).
HTML A rich, formatted document or styled layout.
PDF A print-ready report, letter, or written summary.
Image A chart or diagram (SVG, or PNG/JPEG).
Text A status, a short summary, or plain prose (e.g. a reconciliation status + comments).
JSON Raw structured data, or deeply nested results a table would flatten.

A reconciliation tool might RETURN a text status with comments; an aging report might RETURN an Excel workbook. The result also downloads with one click and is saved to History with its inputs and cost.


9. Connectors, read-only & when to use a Script

  • Read-only by design. LSPL tools can only read and list data — they can never

    create, update, or delete records, and SEND/ALERT/NOTIFY are drafts only (§5). This keeps an AI-run procedure safe to hand to clients.

  • Each workspace connects its own accounts, with credentials encrypted and never

    shared across workspaces.

  • Need to write data or actually send a message? Use a Python Script — the

    only type that can write, and only through a connector explicitly granted write access. A natural pattern is: an LSPL tool drafts and reviews; a Script commits.


10. Two worked examples

A — Accounts-receivable aging (report → Excel)

INPUTS
  asOf: date

FUNC run(asOf)
  --- Build an AR aging summary as of the given date. ---

  VALIDATE
    asOf is a valid date

  DO
    invoices = mcp("xero").call("list_invoices", { status: "AUTHORISED" })

    summary = AI.call(
      "Using the invoices above and the date {asOf}, bucket each open balance into
       Current, 1–30, 31–60, 61–90, and 90+ days overdue. Produce one row per
       customer with a column per bucket and a total column, plus a final totals row."
    )

    LOG "Aged {invoices.length} invoices as of {asOf}"

  RETURN summary   -- rendered as an Excel workbook

B — Support-ticket triage (drafts a reply for review)

This tool runs read-only: the SEND and ALERT appear in the result as a drafted reply and a flag for a human to act on.

FUNC run(ticket)
  --- Resolve a support ticket if possible; otherwise escalate. ---

  VALIDATE
    ticket.subject not empty
    ticket.body not empty

  DO
    classification = AI.call(
      "Classify this ticket: priority (low/medium/high/urgent), category, and
       whether you can resolve it yourself (yes/no)."
    )
    LOG "Classification: {classification}"

    IF classification.canResolve IS yes
      response = AI.call(
        "Draft a specific, actionable reply that resolves the ticket. If you can't,
         say CANNOT RESOLVE and explain why."
      )
      IF response does not contain "CANNOT RESOLVE"
        SEND TO {ticket.customerEmail}
          Subject: Re: {ticket.subject}
          Body: {response}
        EMIT TicketResolved
          ticket_id: {ticket.id}
        RETURN ticket

    ALERT support-team
      Ticket {ticket.id} needs human attention — {classification.priority}.
    EMIT TicketEscalated
      ticket_id: {ticket.id}
      reason:    could not resolve with confidence

  RETURN ticket   -- result shows the drafted reply and/or the escalation flag

11. Best practices for builders

  • State the goal up front in a --- block under FUNC. The AI treats it as the

    mission.

  • Collect inputs, don't assume them. Anything the user should choose belongs in

    INPUTS, validated in VALIDATE.

  • Make AI.calls specific. Spell out the output shape, the buckets, the edge

    cases. Specific instructions → consistent runs.

  • Fix the structure; let the AI fill the words. Use IF/FOR EACH/VALIDATE

    for anything that must be exact; use AI.call for judgement.

  • Pick the output deliberately (§8) and say so in the final step.
  • Keep it read-only. If a tool needs to write or send for real, that's a

    Python Script — design the LSPL tool to draft and review instead.

  • Author for reuse. A good LSPL tool reads the same to two people and runs the

    same across many inputs — that's its advantage over a free-form Prompt.


12. Configured in Netridium, not in your script

A few things are handled by the platform rather than written into an AI Tool:

  • Scheduling — run a tool automatically daily, weekly, or monthly (set on the

    tool's Schedule page), instead of writing a schedule into the script.

  • Who can see and run a tool — controlled by Roles, not in the script.
  • Connections, AI keys, and notification preferences — workspace Settings.

Write the procedure in LSPL; configure when it runs and who can run it in Netridium.


13. Quick reference

Construct Purpose
FUNC run(args) The procedure and its arguments.
--- … --- / -- … Block / inline comments.
INPUTS Declare pre-run form fields.
VALIDATE Preconditions; first failure stops the run (MESSAGE "…").
DO The ordered list of steps.
name = … Assign a value to reuse.
{var} Interpolate a value into a string.
AI.call("…") Have the AI reason/decide here.
IF / ELSE IF / ELSE Branch on conclusions.
FOR EACH x IN list Loop over a collection.
mcp("name").call("tool", {…}) / QUERY Read from a connector (read-only).
LOG "…" Narrate the run.
EMIT Event Output a structured record.
RETURN value Produce the final result (→ Excel/PDF/HTML/text/image/JSON).
SEND / ALERT / NOTIFY Draft & label a message/flag (read-only — no real send).