Claude
Skills
Sign in
Back

greycat

Included with Lifetime
$97 forever

Build, run, and edit GreyCat projects. GreyCat is a statically-typed language plus runtime for graph-persistent, time-series-aware applications. Use when reading or writing `.gcl` source, when the user mentions GreyCat / project.gcl / nodeTime / nodeList / nodeIndex / nodeGeo / @expose / @library, or when the task involves running `greycat <command>`, deploying a project, or reasoning about gcdata/, lib/, files/, webroot/.

Productivity

What this skill does


# GreyCat

GreyCat is **one language and one runtime in one binary**. A project lives in a directory rooted at `project.gcl`. The `greycat` binary compiles it, runs it, serves it as an HTTP server, manages users, and stores its state in `gcdata/`. There is no separate database, queue, or web server.

`.gcl` source files are organized into projects with a single entrypoint named `project.gcl`, whose `@library` / `@include` pragmas (which **must** appear in that file only) form the closure of analyzed modules. Compiled and run by the `greycat` runtime; statically analyzed by `greycat-analyzer`.

## Anti-hallucination rule

GreyCat is **not** Java, Rust, Kotlin, Python, or TypeScript. It has its own conventions and a small grammar. Before writing GCL by analogy to another language, check [`reference/idioms.md`](reference/idioms.md) — most "obvious" guesses are wrong (no `new`, no ternary, no `switch`, no `import`, `private` ≠ "hidden", `->` ≠ `.`, etc.).

When uncertain about a construct: read `lib/std/*.gcl` for real examples, then run `greycat run` against a minimal `project.gcl`. The runtime is the oracle.

## When to read which file

This file covers the 80% you need across language *and* tooling. Drill into a reference file when the task touches its area:

**Language:**

- **[reference/syntax.md](reference/syntax.md)** — Complete grammar reference: every statement, every expression form, operator precedence, literals (string substitution, time `'…'`, typed-suffix numbers).
- **[reference/types.md](reference/types.md)** — Type system in depth: nullability, narrowing, generic invariance, casting, inheritance, `is`/`as`.
- **[reference/stdlib.md](reference/stdlib.md)** — Built-in types by category (collections, node types, time/duration/geo, IO, HTTP, S3, Crypto). Method signatures.
- **[reference/annotations.md](reference/annotations.md)** — Every annotation (`@expose`, `@permission`, `@reserved`, `@volatile`, `@format`, `@test`, `@tag`) and every modifier (`private`, `static`, `abstract`, `native`). Doc-comment tags like `@param`.
- **[reference/idioms.md](reference/idioms.md)** — Idiomatic patterns and common pitfalls (no ternary, no `void`, no `::new()`, `function` slot semantics, `private` semantics, generic invariance).

**Tooling / project / runtime:**

- **[reference/project.md](reference/project.md)** — Project model: entrypoint, `@library` / `@include` resolution, `lib/<name>/` layout, FQN, multi-project workspaces.
- **[reference/cli.md](reference/cli.md)** — `greycat` CLI: every command (`run`, `serve`, `dev`, `build`, `test`, `install`, `codegen`, `user`, `backup`, `restore`, …), every option, the `.env` file.
- **[reference/analyzer.md](reference/analyzer.md)** — `greycat-analyzer` CLI: `lint`, `fmt`, LSP `server`, debug dumps. The pre-commit / definition-of-done tooling.
- **[reference/runtime.md](reference/runtime.md)** — What's alive in a running server: the graph store (`gcdata/`), workers and tasks, the HTTP server (JSON-RPC / path-RPC / `/files` / `webroot`), identity and permissions, the scheduler, backups, logging.
- **[reference/workflow.md](reference/workflow.md)** — Operational recipes: bootstrap a project, add an endpoint, add a persisted type, write tests, evolve schemas, generate SDKs, deploy.
- **[reference/webapp.md](reference/webapp.md)** — Bundling a webapp: `app/` sources + Vite/VitePlus config at the project root + bundle into `webroot/` + `greycat dev`. Calling `@expose`d endpoints from the browser.

## File anatomy

A `.gcl` module is a flat sequence of declarations and pragmas. No top-level expressions. No imports — visibility is governed by the project graph.

```gcl
@library("std", "1.2.3");          // pragma: depend on std at this version (project.gcl only)

/// Doc comment for the type.
type Point<T> extends Shape {      // generic, inheriting
    x: T;                          // attribute (terminated by ; or newline)
    y: T = 0;                      // attribute with init
    private label: String?;        // private attr = read-public, write-private

    fn distance(other: Point<T>): float {
        return sqrt((this.x - other.x) ^ 2 + (this.y - other.y) ^ 2);
    }

    static fn origin(): Point<int> {
        return Point<int> { x: 0, y: 0 };
    }
}

enum Color { red, green, blue }

var threshold: node<float?>;       // module-level var: must be node<T?>, nodeList<T>, nodeIndex<K, V>, nodeTime<T>, nodeGeo<T>

@expose
fn ping(): String {
    return "pong";
}
```

## Project anatomy

```
my-project/
├── project.gcl              # @library + @include pragmas — the ONLY file allowed to carry them
├── .env                     # optional GREYCAT_* config picked up at startup
├── bin/                     # `greycat install` populates with the pinned core binary
├── lib/                     # `greycat install` populates from @library pragmas
│   └── std/                 # the stdlib
├── src/                     # @include("src"); — your code
├── test/                    # @include("test"); — *_test.gcl stripped by `greycat build`
├── files/                   # served at /files/<user>/... — user uploads
├── gcdata/                  # graph storage. DO NOT COMMIT. Back this up.
└── webroot/                 # public static assets, served at /
```

Everything in `bin/`, `lib/`, `gcdata/`, and usually `files/` is gitignored. The source of truth is `project.gcl` + `src/` + (optional) `test/` + `webroot/`. See [reference/project.md](reference/project.md) and [reference/runtime.md](reference/runtime.md) for the role of each directory.

## CLI in one minute

```sh
greycat install     # download libraries and the pinned core binary from project.gcl
greycat serve       # build + run as long-lived HTTP server (port 8080 by default)
greycat dev         # serve + spawn a frontend watcher (vp/vite/--with=<cmd>)
greycat run [fn]    # build + run `fn` (default: `main`). One-shot.
greycat test        # build + run every @test function
greycat build       # produce project.gcp (strips *_test.gcl)
greycat codegen     # generate typed client SDKs (c/ts/python/rust/java)
greycat user list   # admin LMDB-backed user database
greycat backup      # snapshot gcdata/ into ./backup/
greycat restore <archive>
```

Options can be flags (`--name=value`) or env vars (`GREYCAT_NAME=value`). `greycat <command> -h` lists the options that apply, with their currently-resolved values. See [reference/cli.md](reference/cli.md) for the full table.

## Declarations

```gcl
type T {}                         // open user type
private type T {}                 // visible cross-module only via mod::T
abstract type T {}                // cannot be instantiated; methods may lack body
native type T {}                  // runtime-implemented

type Sub extends Base {}          // single inheritance
type G<T, U> {}                   // generics

enum E { a, b(1), "c-with-dash" } // entries optionally carry a value
fn name(p: T): R {}               // function
fn name<T>(p: T): T {}            // generic function
var globalName: T;                // module-level variable (must have type; node-tag only)
```

Each can be prefixed with `///` doc comments and annotations.

### Type bodies

A `type` body contains attributes and methods. There is **no constructor syntax** — instances are built with object-init expressions (see "Construction" below).

```gcl
type User {
    /// Doc on the attribute.
    id: int;
    name: String;
    private password_hash: String;   // outside ctor: read-public, write-forbidden
    static MAX_NAME_LEN: int = 64;   // static (class-level) attribute — readonly

    fn rename(new_name: String) {
        this.name = new_name;        // `this` is implicit in methods
    }

    static fn validate_name(name: String): bool {
        return name.size() <= User::MAX_NAME_LEN;
    }

    native fn hash_password();       // body provided by runtime
    abstract fn validate(): bool;    // requires `abstract type`; no body
}
```

Trailing `;` bet

Related in Productivity