Using

How a System project's scripts reach its own modules: use root.Data.Greeter, use script.Parent.Data.Greeter, a bare use Greeter, or require in a .luau file.

The project

Notes.ssp: the module Data/Greeter.shot and the program Hello.shot.

shot new Notes.ssp
shot write Data/Greeter.shot --project Notes.ssp     the module, its text on stdin
shot write Data/Types.shot --project Notes.ssp       the folder's Types.shot, empty
shot write Hello.shot --project Notes.ssp            the program
shot edit .shotsystem --project Notes.ssp            export Main becomes export Hello

shot tree --project Notes.ssp:

Notes.ssp
./  (the project)
  Data/
    Greeter.shot
    Types.shot
  Hello.shot
  Main.shot

shot run Notes.ssp now runs the export, Hello (One-file projects, THE EXPORT).

A module file

Data/Greeter.shot

types script.Parent.Types

doc { Greets people by name }
module Greeter = {

    doc { How many people it greeted }
    Count : number = 0

    function Hello(name : string) : string
        module.Count += 1
        return "Hello, " .. name .. "!"
    end

}
  • Line 1 is types script.Parent.Types; the folder needs a Types.shot, even an empty one. Without it:
Notes.ssp/Data/Greeter.shot:1   types file not found: script.Parent.Types
  • One table of properties (Name : Type = value) and functions; inside, module is the module (module.Count).
  • Private helpers are plain locals above the declaration (Modules).
  • Class (Classes) and func (Funcs) files work the same.
  • A plain Luau module has no types line and returns its table:

Data/Shout.luau

local Shout = {}

function Shout.Loud(text : string) : string
    return string.upper(text) .. "!"
end

return Shout

use root.Data.Shout reaches it too: print(Shout.Loud("hello")) prints HELLO!.

A script uses it

Hello.shot, a program script (it declares nothing):

use root.Data.Greeter

print(Greeter.Hello("Ada"))
print(Greeter.Hello("Grace"))
print(Greeter.Count .. " greeted")

It checks with 0 errors and prints:

Hello, Ada!
Hello, Grace!
2 greeted

use root.Data.Greeter is short for local Greeter = require(root.Data.Greeter): the local takes the last name. root is the root instance (One-file projects, ROOT AND SCRIPT).

Every form

Each works as Hello.shot's first line:

use root.Data.Greeterany .shot file: the path from the project's root
use script.Parent.Data.Greeterfrom the file's own folder (Hello.shot's is the root)
local Greeter = require(root.Data.Greeter)the same as use root.Data.Greeter
local Greeter = require(script.Parent.Data.Greeter)Luau's form, and the only one in a .luau file

script is the file's own instance, script.Parent its folder.

A bare name finds the nearest file so named: the file's folder, then each folder above, never below. So use Greeter works in Data and under it:

Data/Welcome.shot

types script.Parent.Types

use Greeter

doc { The first line a new user sees }
module Welcome = {

    function Line(name : string) : string
        return Greeter.Hello(name) .. " Your notes are ready."
    end

}

Hello.shot

use root.Data.Welcome

print(Welcome.Line("Ada"))

prints:

Hello, Ada! Your notes are ready.

In a .LUAU file

A .luau file has no use or root; it requires by its place in the tree. Hi.luau, at the root, made the export (export Hi):

local Greeter = require(script.Parent.Data.Greeter)

print(Greeter.Hello("Ada"))

It prints Hello, Ada!. With require(root.Data.Greeter), check gives

Notes.ssp/Hi.luau:1:25   root.Data.Greeter: root is a .shot file's and a scenario's, so in a .luau file it is nil at run; a .luau file reaches its project by its place in the tree: script.Parent.Data.Greeter

and the run stops:

error: Hi.luau:1: attempt to index nil with 'Data'
  at Hi.luau:1

Scenarios are the one .luau files with root (Scenarios).

A dot for a module, a colon for a service

A module has no self: call it with a dot, Greeter.Hello("Ada"). Greeter:Hello("Ada") gives

Notes.ssp/Hello.shot:3:7   TypeError: Expected this to be 'string', but got 'Greeter'
Notes.ssp/Hello.shot:3:21   TypeError: Argument count mismatch. Function 'Greeter.Hello' expects 1 argument, but 2 are specified

Services, instances and what they give back take a colon: FileService:WriteAsync(path, text), child:WaitAsync() (Services, ProcessService).

The Roblox forms and their errors

The language pages' Roblox examples write @shot.Wallet.Bank: here, root.Wallet.Bank. As Hello.shot's line 1, each form below gives the error under it.

use @shot.Data.Greeter, or local Greeter = require(@shot.Data.Greeter):

Notes.ssp/Hello.shot:1   @shot is the Roblox target's: in a System project a path from the project root starts with root, like use root.Utils.Mop

local Greeter = require("./Data/Greeter"):

Notes.ssp/Hello.shot:1:17   require("./Data/Greeter"): a string require is @<Alias> from the project's header, or @shotsystem/<Service>, so a run refuses a file path; a module of this project comes by its place in the tree: use script.Parent.Data.Greeter

use Greeter at the root:

Notes.ssp/Hello.shot:1   use Greeter: no Greeter in this folder or any folder above it (use looks at each folder's own files and folders, up to the project root); it is in Data: use root.Data.Greeter

import Greeter from script.Data.Greeter, plus a TypeError per line naming Greeter:

Notes.ssp/Hello.shot:1   import only works in a Types file: move it to this folder's Types.shot (every file of the folder sees what it imports)
Notes.ssp/Hello.shot:3:7   TypeError: Unknown global 'Greeter'; consider assigning to it first

import only brings types, in a Types.shot (Types).

shot run stops at a refused use line or string path:

error: Hello.shot:1: @shot is the Roblox target's: in a System project a path from the project root starts with root, like use root.Utils.Mop
  at Hello.shot:1
error: Hello.shot:1: require("./Data/Greeter"): Notes.ssp has no external of that name (a string require is @<Alias> from the project's header, or @shotsystem/<Service>)
  at Hello.shot:1

require(@shot.Data.Greeter) still runs: only check refuses it.