# Aussom AI Guide (Aussom CLI)

**What this file is:** a briefing for an AI coding assistant that has been
asked to write Aussom code for the Aussom CLI. Aussom is a small language
with almost no presence in model training data, so a model writing it from
instinct will produce code that looks right and does not run. This guide
tells you where the real API documentation lives on the machine you are
working on, how to check your code before you hand it over, and which
specific habits carried over from Java, JavaScript, and Python will break.
Read it before writing Aussom, not after the first error.

If you are writing an app for **Aussom Server** instead, read
`aussom-server-ai-guide.md`. That is a different runtime with a different
module set, though the core language rules here still apply.

---

## 1. Find the documentation before you write anything

Do not guess method names. Aussom's standard library is documented in full,
and the docs ship with the install. Look up the class you are about to use.

### Local install locations

The CLI installs to a fixed location per platform. The documentation is in
a `docs` directory inside the application directory.

| Platform | Documentation directory |
| --- | --- |
| Linux | `/opt/aussom/lib/app/docs/` |
| macOS | `/Applications/aussom.app/Contents/app/docs/` |
| Windows | `C:\Program Files\aussom\app\docs\` |

### Finding it on any platform

If the paths above do not exist, ask the CLI where it lives. This works
everywhere and survives a non-standard install:

```
$ aussom -jl
/opt/aussom/lib/app/aussom-1.2.4.jar
```

The `docs` directory is a sibling of that jar. In the example above the
docs are at `/opt/aussom/lib/app/docs/`.

### What is in the docs directory

```
docs/
  markdown/          <- API reference, one file per module
    lang.aus.md      <- core types: string, list, map, int, c, lang
    file.aus.md
    os.aus.md
    ...
  html/              <- the same reference plus written guides, rendered
  guides.json        <- index of the written guides
```

`markdown/` is what you want. Each file documents one module, and the
format is consistent:

```
## class: list

[842:14] (extern: com.aussom.types.AussomList) **extends: object**

Implements list datatype methods.

#### Methods

- **add** (`ItemToAdd`)

	> Adds the provided item to the list.

	- **@p** `ItemToAdd` is any item to add.
	- **@r** `this` object
```

To check whether a method exists, grep the module file:

```
$ grep -n "^- \*\*" /opt/aussom/lib/app/docs/markdown/lang.aus.md
```

Start with `lang.aus.md`. It holds every core type you will touch:
`string`, `list`, `map`, `int`, `double`, `bool`, `Buffer`, `Date`,
`callback`, `exception`, plus the `c` console class and the `lang` static
class.

### Web fallback

If the machine has no local install, use the online documentation:

- Aussom CLI: https://aussom-lang.com/docsProduct?product=aussom

Individual pages follow this pattern:

```
https://aussom-lang.com/docPage?product=aussom&page=common/written/language-overview.md&title=Language%20Overview
```

Large pages are better fetched with `curl` and read in sections than
loaded whole.

---

## 2. Verify your code before you hand it over

Aussom has two failure stages, and passing the first does not mean passing
the second. Check both.

### Parse check

```
$ aussom -d -o /tmp/docout myfile.aus
```

`-d` generates documentation, which requires a full parse. A syntax error
is reported as `PARSE_ERROR` with a line and column. Options must come
**before** the file name or the CLI prints its help text instead of
running.

```
[error] broken.aus [4]: PARSE_ERROR: Unknown symbol found at line 4 column 21.

instead expected token classes are [LBRACKET]
```

`[LBRACKET]` means the parser wanted a `{`. That is almost always an
unbraced `if` or loop body.

### Run it

A parse check does not catch undefined names, wrong method names, or bad
call signatures. Those are runtime errors, and they only fire when that
line actually executes.

```
$ aussom myfile.aus
```

This is the trap that matters most. Consider `continue`, which is not an
Aussom keyword:

```aussom
for (x : [1,2,3]) {
    if (x == 2) { continue; }
    c.println(x);
}
```

This **passes the parse check**. `continue` is parsed as an identifier, so
the syntax is legal. At runtime it fails the moment `x` is 2:

```
id: UNDEFINED_NAME
text: astObj.evalObjStart(): Undefined name 'continue'.
```

Any code path you did not execute is code you did not test. Run the
program, not just the parser.

### Run the tests

```
$ aussom -t myTest.aus      # one test class
$ aussom -ta myTest.aus     # every test class loaded
```

Test classes use `@Test` on the class and on each method, with `@Before`,
`@After`, `@BeforeEach`, `@AfterEach`, and `@OnTestFail` hooks. Assertions
come from the `test` static class (`test.expect`, `test.expectNotNull`,
`test.expectString`, and so on). See `aunit.aus.md`.

### Testing GUI apps

Do not hand over an untested GUI app, and do not test one by telling the
user to click around. Aussom ships a UI test module for each toolkit, and
both run under `aunit` like any other test.

| Toolkit | Module | Full guide |
| --- | --- | --- |
| JavaFX | `testfx` | `testfx-usage.md` |
| GTK4 | `gtktest` | `gtktest-usage.md` |

Both work the same way: give every widget you intend to assert on a stable
id when you build the UI, look it up by selector in the test, act on it,
then verify.

#### JavaFX with `testfx`

The lifecycle is fixed, and the order matters:

```aussom
include aunit;
include fx;
include fx.Label;
include fx.Button;
include testfx;

@Test(name = "Counter")
class counterTest : test {
    private app = null;

    @Before
    public runBefore() {
        testfx.setHeadless(true);          // must precede fx.fxApp()
        this.app = fx.fxApp("Counter", 300, 200);
        // ... build the UI, setId() on anything you will assert on ...
        this.app.show(false);
        testfx.setup(this.app);
    }

    @After
    public runAfter() {
        testfx.cleanup();
        fx.runLater(::closeApp);
        fx.shutdown();
    }

    public closeApp() { this.app.close(); }

    @Test(name = "Click increments the count.")
    public clickIncrement() {
        testfx.clickOn("#incBtn");
        testfx.verifyHasText("#counterLabel", "Count: 1");
        return this.expectBool(true);
    }
}
```

Selectors are `#id`, `.cssClass`, or bare visible text. Actions include
`clickOn`, `doubleClickOn`, `rightClickOn`, `write`, `push`, `eraseText`,
`moveTo`, `drag`, `dropTo`, `scrollUp`, and `scrollDown`. Assertions
include `verifyHasText`, `verifyExists`, `verifyNotExists`,
`verifyVisible`, `verifyInvisible`, `verifyEnabled`, `verifyDisabled`,
and `verifyFocused`.

`testfx.setHeadless(true)` switches JavaFX to the Monocle platform so no
window appears. It **must** be called before `fx.fxApp()`, because the
toolkit reads the system properties when it first initializes; calling it
afterward does nothing. The same thing can be done from the command line
instead:

```
$ aussom -jo "-Dglass.platform=Monocle -Dmonocle.platform=Headless" myTest.aus
```

Headless JavaFX has real limits, and they are easy to mistake for bugs in
your code:

- **Simulated input does not register.** TestFX robot clicks and typing do
  not reach the app under Monocle headless, so a label driven by a
  `clickOn` stays at its initial text. Test the handler logic directly, or
  run those cases headed.
- **`WebView` cannot be constructed at all** headless; it needs native
  WebKit that Monocle does not provide. Those tests must run headed.
- **`Alert`, `TextInputDialog`, and `ChoiceDialog` must be constructed on
  the FX thread** via `fx.runLater(...)`. Building them from the test
  thread throws `constructor instantiation exception: null`.
- **`SubScene` contents are not initialized**, so 3D nodes are not
  reachable by selector lookup. Verify those ids on the wrapper object
  directly.
- **Fixtures load relative to the working directory**, not to the test
  file. Running a suite from the wrong directory produces misleading
  errors like `Object 'cnull' has no overload of 'getUrl'` rather than a
  missing-file message. Check the working directory before believing a
  regression.

#### GTK4 with `gtktest`

`gtktest` fills the same role for GTK apps. Build the window, present it,
then target it:

```aussom
include aunit;
include gtktest;
include gtk.gtk.functions;
include gtk.gtk.widget;
include gtk.gtk.window;
include gtk.gtk.button;

@Test(name = "GtkTest Tests")
class gtkFixtureTest {
    public window = null;

    @Before
    public runBefore() {
        GtkApi.init();
        this.buildWindow();          // set_name() on anything you assert on
        this.window.present();
        gtktest.setup(this.window);
        gtktest.waitForDraw(this.window);
        return null;
    }

    @After
    public runAfter() {
        gtktest.cleanup();
        if (this.window != null) { this.window.close(); }
        return null;
    }
}
```

`GtkApi` is a **static** class, so it is used as `GtkApi.init()`. Writing
`new GtkApi()` fails with "Cannot instantiate static class 'GtkApi' with
'new'". Older example code in the repository still uses the `new` form and
no longer runs. Widgets also need their own module included: calling
`asWidget()` without `include gtk.gtk.widget;` fails with "Cannot
instantiate object of type 'GtkWidget', class definition not found in
engine".

Selectors are richer than TestFX: `#name` (buildable id or widget name),
`.klass` (CSS class), `!role` (accessible role), `"text"` (visible text),
and a bare GTK type name such as `Button`. Alongside the usual `verify*`
assertions it adds `verifyAccessibleRole` and `verifyAccessibleProperty`,
plus `capture`, `captureWindow`, `captureScreen`, and
`startRecording` / `stopRecording` for screenshots and frame recording.

GTK specifics worth knowing:

- **Pump the event loop before asserting.** UI state that updates
  asynchronously will not be visible until you call `gtktest.pump()` or
  `gtktest.pumpUntil(::predicate, 5000)`.
- **Prefer the X11 backend.** Under a pure Wayland session, anything that
  waits on the frame clock -- `waitForDraw`, `capture`, `captureWindow`,
  `startRecording` -- is compositor-dependent and can stall. Run tests as:

  ```
  $ GDK_BACKEND=x11 aussom -t tests/myGtkTest.aus
  ```

- **Real input is optional and conditional.** `gtktest.useRobot(true)`
  routes actions through the X11 XTest extension instead of emitting GTK
  signals. It only works on Linux with `DISPLAY` set and the X11 backend
  active. Gate any robot-dependent test with `gtktest.robotAvailable()` so
  it skips cleanly elsewhere. Without robot mode, `clickOn` is a semantic
  signal emission, which is enough for most assertions.

### Script mode

For a quick experiment you do not need a class. `-s` allows top-level
statements:

```
$ aussom -s scratch.aus
```

This is the fastest way to confirm a method name or an operator before you
commit to it in real code.

---

## 3. The language in one page

### File shape

Every `.aus` file is classes. Execution starts at `public main(args)`.

```aussom
include sys;

class hello {
    public main(args) {
        c.println("Hello World");
        return 0;
    }
}
```

`c` and `lang` are always available with no `include`. Everything else
(`sys`, `file`, `os`, `http`, ...) must be included explicitly.

### Comments

`//` for a line and `/* */` for a block. `#` is **not** a comment; it is
the count operator. Aussom Doc comments use `/** ... */` with `@p` for a
parameter and `@r` for the return.

### Types

`string`, `int`, `double`, `bool`, `list`, `map`, `null`, plus `Buffer`,
`Date`, and `callback`. Variables are not declared with a type:

```aussom
name = "Bob";
count = 5;
items = [1, 2, 3];
lookup = {"a": 1, "b": 2};
```

Get a value's type with `lang.type(x)`, which returns a type name for
primitives and the class name for objects.

Map values can be read with either `get` or dot access, which is
convenient for parsed JSON:

```aussom
mp = json.parse("{\"x\": 5}");
mp.x           // 5
mp.get("x")    // 5
```

Use `mp.containsKey("x")` before reading a key that may be absent.

### Operators

| Operator | Meaning |
| --- | --- |
| `+ - * / %` | arithmetic; `/` always produces a double (`7 / 2` is `3.5`) |
| `~/` | floor division (`7 ~/ 2` is `3`) |
| `#x` | count: string length, list size, map size |
| `@=` | append to a list (`lst @= 3;`) |
| `&&` `\|\|` `!` | logical |
| `&` `\|` | bitwise and / or |
| `==` `!=` `<` `>` `<=` `>=` | comparison |
| `?x` | missnull: yields null instead of failing on a missing value |
| `::name` | a callback bound to `this` |
| `instanceof` | type test, with the type name **quoted** |

There is no ternary `? :`, no `^`, and no `<<` or `>>`.

### Control flow

Every body must be braced. There are no single-statement bodies.

```aussom
if (x > 0) {
    c.println("positive");
} else {
    c.println("zero or less");
}

while (i < 10) { i += 1; }

for (i = 0; i < 10; i += 1) { c.println(i); }

for (item : items) { c.println(item); }

switch (v) {
    case 1: { out = "one"; }
    case 2: { out = "two"; }
    default: { out = "other"; }
}
```

`break` exists. `continue` does not.

### Classes

```aussom
class Animal {
    public name = "";
    public Animal(string n) { this.name = n; }
    public speak() { return this.name + " makes a sound"; }
}

class Dog : Animal {
    public Dog(string n) { this.name = n; }
    public speak() { return this.name + " barks"; }
}
```

Members are always reached through `this.`. A bare `name` inside a method
is an undefined name, not the member.

Aussom supports multiple inheritance: `class C : A, B` is legal, and the
first parent wins when two parents define the same method.

A `static class` is called without `new`:

```aussom
static class util { public double(int n) { return n * 2; } }
// util.double(4)
```

`static` is a class-level modifier only. There is no `static public`
method.

### Callbacks

`::methodName` creates a callback bound to the current object. Call it
with plain arguments.

```aussom
class runner {
    public got = 0;
    public onDone(v) { this.got = v; }
    public start() {
        cb = ::onDone;
        cb.call(42);
    }
}
```

### Errors

`throw` accepts any value, most often a string. The caught value is an
`exception` object with five useful parts: `getLineNumber()`,
`getExceptionType()`, `getId()`, `getText()`, and `getStackTrace()`.

```aussom
try {
    this.risky();
} catch (e) {
    c.println(e.getId() + ": " + e.getText());
}
```

When reporting an error, print more than `getText()`. The id and the stack
trace are usually what identify the problem. Note that `getId()` is empty
for a value you threw yourself; it is populated for runtime errors raised
by the interpreter, where it carries codes like `UNDEFINED_NAME` or
`FUNCT_NOT_FOUND`.

---

## 4. Traps

These are the mistakes a model actually makes when writing Aussom. Each one
is confirmed against the current runtime.

### Sizes and lengths

`length()` is a **string** method. Lists and maps use `size()`.

```aussom
"hello".length()    // 5
[1,2,3].size()      // 3
{"a":1}.size()      // 1
```

There is no `.length` property on anything; JavaScript habits fail here.
`#x` works on all three and is the shortest correct answer:

```aussom
#"hello"    // 5
#[1,2,3]    // 3
```

### `continue` does not exist

Covered in section 2. Invert the condition instead:

```aussom
// wrong
for (x : items) {
    if (x.skip) { continue; }
    this.handle(x);
}

// right
for (x : items) {
    if (!x.skip) { this.handle(x); }
}
```

### Bodies must be braced

`if (buf.size() == 0) break;` is a parse error. Write
`if (buf.size() == 0) { break; }`. This applies to `if`, `else`, `while`,
and `for`.

### No ternary operator

`x = (a == 1) ? "y" : "n";` fails at parse. Assign a default and reassign:

```aussom
label = "n";
if (a == 1) { label = "y"; }
```

### `==` on lists and maps is identity

`[1,2] == [1,2]` is **false**. To compare contents, compare sizes and then
walk the elements. This also means `test.expect(someList, [1,2])` fails
even when the elements match; compare a computed bool instead.

### `instanceof` needs a quoted type name

```aussom
if (d instanceof 'Animal') { ... }    // right
if (d instanceof Animal) { ... }      // wrong
```

### Do not shadow the built-in static classes

A local variable named `c` resolves to the console class, not your
variable, and the error is confusing:

```
[NO_OPERATION] :: astObj.evalObjStart(): Static class object found
but no child function or property provided.
```

Avoid these names for locals and parameters: `c`, `sys`, `os`, `file`,
`lang`, `math`, `aji`, `json`, `io`, `net`, `http`, `time`, `date`,
`list`, `map`, `string`, `thread`, `reflect`, `out`, `secman`,
`securitymanager`, `Int`, `Double`, `Bool`, `Date`, `Buffer`.

If you need a short name, `cv` or `val` is safe.

### Strings do not coerce to numbers with `+`

`0 + "23"` is the string `"023"`, not `23`. Convert explicitly:

```aussom
n = "23".parseInt();
d = "2.5".parseDouble();
b = "true".parseBool();
```

### Method names that differ from Java and JavaScript

| You might write | Aussom has |
| --- | --- |
| `.substring(a, b)` | `.substr(a, b)` |
| `map.keys()` | `map.keySet()` |
| `file.isDirectory(p)` | `file.isDir(p)` |
| `.toInt()` | `.parseInt()` |
| `list.length` | `list.size()` or `#list` |
| `list.push(x)` | `list.add(x)` or `lst @= x` |

`file.rmr(path)` is the recursive delete; `file.rm` is not recursive.
`file.walk(path)` throws on a missing path, so guard with `file.exists`
first.

### String escapes

`\n`, `\t`, `\r`, and `\uXXXX` work. `\033`, `\x1b`, and `\e` all fail at
parse with `Illegal character <92>`. The ANSI escape byte is `"\u001b"`.

### The `object` annotation does not mean "any type"

`public extern sha256(object Data);` only matches class instances. A plain
string will not dispatch to it. For a parameter that should accept
anything, leave it untyped:

```aussom
public sha256(Data) { ... }
```

### Console output methods differ

`c.info(x)` prints `[info] x`. `c.println(x)` prints `x` and a newline
with no prefix. `c.print(x)` prints raw with no newline, which is what an
in-place status line needs. `os.out(x)` is the same as `c.println(x)`.

### Async assertions must poll

A callback or timer test that sleeps a fixed interval and then asserts once
will flake under load. Poll for the condition with a generous timeout
instead.

---

## 5. Module index

Include a module before using it, for example `include file;`.

`aji`, `app`, `aunit`, `cliparser`, `codec`, `concurrent`, `cssfx`,
`curses`, `file`, `fx`, `fxgl`, `glib`, `gtk`, `gtktest`, `handlebars`,
`http`, `jansi`, `javabuild`, `javatools`, `jdbc`, `lang`, `markdown`,
`math`, `os`, `panama`, `reflect`, `socket`, `sslsocket`, `sys`, `testfx`,
`thread`, `udpsocket`, `util`, `xml`, `yaml`, `zip`

Most have a matching `<name>.aus.md` in the docs `markdown` directory.
`fx`, `fxgl`, and `gtk` are larger and also have a subdirectory of their
own namespaced modules, so browse the directory rather than expecting one
flat file. Read the docs before using a module; several have names that do
not match the Java or JavaScript equivalent you may be expecting.

---

## 6. Checklist

Before handing over Aussom code:

1. Looked up every stdlib method in `docs/markdown/`, rather than assuming.
2. Braced every `if`, `else`, `while`, and `for` body.
3. Used `size()` for lists and maps, `length()` for strings, or `#` for all.
4. No `continue`, no ternary, no `.substring`, no bare member access.
5. No local named `c`, `file`, `list`, `map`, or any other static class.
6. Ran `aussom -d -o <dir> <file>` and got no `PARSE_ERROR`.
7. Ran the program and exercised the branches, not just the happy path.
8. For a GUI app, wrote `testfx` (JavaFX) or `gtktest` (GTK4) tests and ran
   them, rather than asking the user to click through it. Gave every
   asserted widget a stable id, and did not rely on simulated input under
   JavaFX headless.
