Back to .md Directory

at` Language Agent Skill

name: at-language-expert

May 2, 2026
0 downloads
1 views
ai agent llm
View source

name: at-language-expert description: Essential procedural knowledge and constraints for writing, debugging, and understanding the at programming language.

at Language Agent Skill

This skill provides the mandatory procedural knowledge required to successfully write and debug at code. at is a fast, strictly-typed language built specifically for AI agents.

Design Philosophy

at is designed around what makes agents succeed, informed by A Language For Agents:

  • Context without LSP: Types are explicit in function signatures and return types. You never need an LSP to understand what a function accepts or returns. Local variables use inference to save tokens, but the public API is always readable.
  • Braces over whitespace: at uses { } delimiters, not significant whitespace. This avoids the token-efficiency and surgical-edit problems that LLMs have with indentation-sensitive languages.
  • Results over exceptions: Prefer Result<T, E> and ? propagation. try/catch/finally exists as an escape hatch but Result is the idiomatic error-handling pattern. Agents should default to returning Result types.
  • Explicit effects: Side effects (network, filesystem, time, randomness) must be declared via needs { ... } blocks. This makes mocking trivial in tests and gives agents clear signals about what a function touches.
  • Minimal diffs: Trailing commas are supported everywhere (arrays, maps, match arms, function params). Format code vertically to keep diffs single-line.
  • Greppable imports: All imports require aliasing (import "x" as y;). Every symbol use is prefixed with its module name (like Go's context.Context), making code searchable with basic tools like grep or sed.
  • Local reasoning: Each file is self-contained. No implicit globals, no re-exports, no barrel files. If you read a file, you can understand it without loading other files.
  • No macros: at has no macro system. Code generation is unnecessary when the cost of writing code is low.
  • No re-exports or barrel files: Every import points to the file that defines the symbol. One-to-one mapping from declaration to usage.
  • Dependency-aware builds: No circular imports. Packages have clear boundaries. Test results are aggressively cached.
  • Deterministic tests: Tests can pin time and randomness (using time.fixed; using rand.seeded;), eliminating flakiness by design.
  • Single failure condition: at check type-checks and lints in one pass. Code either passes or fails — there is no "compiles but has type errors" state. at test runs all tests. Two commands, zero ambiguity.

Critical Constraints (Read First)

  1. Explicit Return Types Required: Every function MUST declare its return type fn name() -> type {.
  2. Mandatory Import Aliasing: You MUST alias all imports (import "./utils.at" as utils;). There are no global imports, no re-exports.
  3. Capability Sandboxing: If a script touches the network, filesystem, or time, you MUST declare a needs { ... } block.
  4. Token Efficiency: The compiler infers local variables. Use let x = 5; instead of let x: int = 5; to save tokens.
  5. Mutation uses set: Variables are immutable by default. Use set x = newValue; to mutate (not let mut).
  6. Semicolons required: All statements end with ;.
  7. Match arms use commas: Match arms are separated by , (not newlines).
  8. No macros: There is no macro system. Write explicit code.
  9. Prefer Result over try/catch: Use Result<T, E> and ? for error handling. Avoid try/catch unless wrapping FFI or legacy code.

1. Syntax Overview

Variables & Types

let immutable = 10;
let mutable = 20;
set mutable = 30;       // `set` for mutation, not `let mut`

// Type inference handles these automatically
let array = [1, 2, 3];
let empty = [];          // empty array literal
let m = map {};          // empty map literal
let m2 = map { "key": "value" };

Functions & Tests

Tests are colocated and execute at highly-optimized speeds with at test.

fn add(a: int, b: int) -> int {
    return a + b;
}

test "adds numbers" {
    assert(add(1, 2) == 3);
}

Control Flow

if a > b {
    // ...
} else {
    // ...
}

for item in array {
    // ...
}

while condition {
    // ...
}

Error Handling

Use Result<T, E> and ? for early returns. This is the idiomatic pattern — agents should default to this over try/catch.

fn divide(a: int, b: int) -> Result<int, string> {
    if b == 0 {
        return Err("Division by zero");
    }
    return Ok(a / b);
}

fn calculate() -> Result<int, string> {
    let result = divide(10, 2)?;
    return Ok(result + 1);
}

Enums & Pattern Matching

enum Shape {
    Circle(float),
    Rect(float, float),   // multi-field variants supported
    Point,                 // no-payload variant
}

fn area(s: Shape) -> float {
    return match s {
        Shape::Circle(r) => 3.14159 * r * r,
        Shape::Rect(w, h) => w * h,
        Shape::Point => 0.0,
    };
}

Higher-Order Functions

map, filter, and reduce are compiler-inlined (not regular builtins):

let nums = [1, 2, 3, 4, 5];
let doubled = map(nums, |x| x * 2);
let evens = filter(nums, |x| x % 2 == 0);
let total = reduce(nums, 0, |acc, x| acc + x);

2. Builtins Reference

Core

print(value), assert(condition), assert_eq(a, b), len(collection), type_of(value)

Math

abs(n), min(a, b), max(a, b), floor(f), ceil(f), round(f), pow(base, exp), sqrt(f), sum(array)

String

contains(haystack, needle) (works on arrays and strings), slice(arr, start, end), split(str, delim), trim(str), to_upper(str), to_lower(str), substring(str, start, end), join(array, sep), replace(str, old, new), starts_with(str, prefix), ends_with(str, suffix), repeat(str, n), parse_int(str), parse_float(str), to_string(value)

Character

char_code(str), from_char_code(n), is_digit(str), is_alpha(str), is_upper(str), is_lower(str)

Array

append(arr, value), sort(arr), reverse(arr), index_of(arr, value), count(arr, value), range(start, end)

Map

keys(map), values(map)

Regex

regex_match(str, pattern) -> bool, regex_find(str, pattern) -> array<string>, regex_replace(str, pattern, replacement) -> string

Note: Use {{ to escape literal { in regex patterns inside string literals (e.g., "[0-9]{{3}}" for the regex [0-9]{3}).

Option & Result

some(v), none(), is_some(opt), is_none(opt), ok(v), err(v), is_ok(res), is_err(res)

3. Explicit Effects & Sandboxing

Agents execute in a secure sandbox. You cannot perform side-effects without declaring them statically.

needs { network, fs } // MUST be declared if you fetch or read files

import "std/http.at" as http;

fn fetch_data() -> Result<string, string> {
    return http.get("https://example.com");
}

For test determinism, declare deterministic environments:

using time.fixed;
using rand.seeded;

4. Code Generation Checklist for LLMs

Before modifying or generating at code, verify:

  • Mutation: Use set x = value; to mutate, not let mut.
  • Error handling: Use Result<T, E> and ?, not try/catch.
  • Formatting: Multi-element arrays, tuples, and maps MUST be formatted vertically to preserve diff-stable trailing commas.
  • Aliasing: Did you alias all imports? (import "x" as y;)
  • Effects: Did you declare needs { ... } at the top of the file if accessing external systems?
  • Tests: Are you writing colocated test "name" { assert(...); } blocks for your functions?
  • Types: Did you let the compiler infer types for local variables using let x = ...?
  • Semicolons: All statements end with ;.
  • Match commas: Match arms separated by ,.
  • Mixed arithmetic: int and float can be mixed freely (int is promoted to float).
  • No macros: Write explicit code. There is no macro system.
  • Local reasoning: Each file should be self-contained. No re-exports, no barrel files.

5. Development CLI

As an agent, you can use these tools to iteratively validate your code:

  • at check - Type-check and lint in one pass (instant, catches all errors before runtime)
  • at test <file|dir> - Run tests in a file or recursively in a directory (aggressively cached, very fast feedback loop)
  • at run <file> - Execute a script
  • at fix - Auto-formats code and fixes lints

6. Limitations

These are things at intentionally does not support or has not yet implemented:

  • No classes or inheritance. Only structs and enums (algebraic data types).
  • No mutable references. All data is immutable/copy-on-write (Rc-shared). set creates new copies.
  • No standard I/O beyond print. No read_line, no file I/O builtins (would require fs capability and corresponding builtins which do not exist yet).
  • No hash/set data structure. Only arrays and ordered maps. Use a map with dummy values as a workaround.
  • No package manager. Remote imports are direct URL fetches with caching.
  • No null. Uses option (some/none) instead.
  • No implicit returns. Must use return keyword (though block expressions have implicit tail values).
  • Integer arithmetic is overflow-checked. Large computations will error rather than wrap.
  • Single-threaded. Async is cooperative, not parallel. No OS-level threading.
  • No recursion depth guarantees. A configurable max_frames limit exists for sandboxed execution.
  • String interpolation uses {expr}. Use {{ to write a literal { in strings (relevant for regex patterns with quantifiers like {3}).

Related Documents