In this page
GreyCat Server
Introduction
To empower digital twin, GreyCat is not only a Runtime but also a Server.
Any function can be exposed to remote procedure call (RPC) by adding an @expose pragma
@expose
fn compute(p: int): int {
return 3 + 5 + p;
}
fn main() {
println(compute(2));
}
This minimal code snippet already defines a server (–user=root impersonates the root user and bypasses authentication, more on this later)
greycat serve --user=root
# 10
# INFO 2026-10-27T09:28:06.293689Z GreyCat is serving on port: 8080, runtime: 8.4.594-stable+fe2b2a3fc
# WARN 2026-10-27T09:28:06.293715Z Impersonate mode with user: root
GreyCat server can be queried through an HTTP API.
The parameters for the endpoint can be url encoded:
curl -X POST -d "[100]" http://localhost:8080/project::compute
> 108
Or the parameters for the endpoint can be JSON encoded:
curl -X POST --json "[100]" http://localhost:8080/project::compute
> 108
From a terminal, greycat call does the same without writing the request, and authenticates with
the root token of the project (see Call):
greycat call project::compute 100
> 108
Functions and error handling
fn sub_process() {
throw "stop here";
}
@expose
fn computeWithSub(p: int): int {
sub_process();
return 3 + 5 + p;
}
fn main() {
var res = computeWithSub(2);
println(res);
}
In this example, sub_process and computeWithSub share error handling management, leading to the following error stack
greycat run --format=json
{
"message": "stop here",
"stack": [
{ "module": "project", "function": "main", "line": 10, "column": 33 },
{ "module": "project", "function": "computeWithSub", "line": 6, "column": 18 },
{ "module": "project", "function": "sub_process", "line": 2, "column": 23 }
]
}
Function entrypoint == Transaction
Every exception thrown activates a rollback mechanism, leaving the temporal graph unchanged
var counter: node<int?>;
@expose
fn inc_count() {
println(*counter);
counter.set((counter.resolve() ?? 0) + 1);
throw "my bad";
}
This is illustrated in this example, where multiple calls do not alter the counter due to the following exception
greycat run inc_count --format=json
# null
# {"message":"my bad","stack":[{"module":"project","function":"inc_count","line":7,"column":20}]}
greycat run inc_count --format=json
# null
# {"message":"my bad","stack":[{"module":"project","function":"inc_count","line":7,"column":20}]}
Exposed functions are for short computations!
Like many API-oriented frameworks, GreyCat adds a timeout to remote function calls (default of 20s, configurable with --request_ttl)
@expose
fn heavy_computation() {
while (true) {
// noop
}
}
any call through the HTTP API will then result in a timeout exception (and therefore rollback)
greycat serve --user=root
curl -X POST http://localhost:8080/project::heavy_computation
# {"message":"timeout","stack":[{"module":"project","function":"heavy_computation","line":3,"column":16}]}
timeout is similar for write and read function entrypoints; this enhances the server for multi-user experience
Long running functions? Task is the answer!
An in depth explanation can be found here
Env variables
GreyCat supports a wide range of environment variables that can either be defined on the cli or in an .env file
| Command-Line Option | Environment Variable | Description |
|---|---|---|
| –log= |
GREYCAT_LOG=info | Level of log (none,error,warn,info,trace) |
| –cache= |
GREYCAT_CACHE=(75% of memory) | Size of cache in bytes (if no suffix, default is MiB) |
| –store= |
GREYCAT_STORE=1.0GB | Size of store in bytes (if no suffix, default is MiB) |
| –store_paths= |
GREYCAT_STORE_PATHS=(null) | Path leveraged to store zone files |
| –http_threads= |
GREYCAT_HTTP_THREADS=3 | Number of workers dedicated to handle http connections |
| –workers= |
GREYCAT_WORKERS=(CPU count) | Task workers, split into the small, medium and large classes |
| –workers_small= |
GREYCAT_WORKERS_SMALL=auto | How many of --workers run small tasks, which RPC calls are (auto: 20%, at least 1 from 2 workers) |
| –workers_large= |
GREYCAT_WORKERS_LARGE=auto | How many of --workers run large tasks. They also run medium and small ones when idle (auto: 10%) |
| –cache_ratio_small= |
GREYCAT_CACHE_RATIO_SMALL=0.40 | Object cache of a small worker, relative to a medium one (must be > 0) |
| –cache_ratio_large= |
GREYCAT_CACHE_RATIO_LARGE=3.00 | Object cache of a large worker, relative to a medium one (must be > 0) |
| –metrics_host_step= |
GREYCAT_METRICS_HOST_STEP=1min | Period of the HostMetric record, when the host metric is on (GREYCAT_METRICS): host CPU, memory, disk, zones and worker classes |
| –port= |
GREYCAT_PORT=8080 | Port used by serve command |
| –webroot= |
GREYCAT_WEBROOT=webroot | Webroot to serve |
| –key= |
GREYCAT_KEY=(null) | Path to private key |
| –keysafe= |
GREYCAT_KEYSAFE=(null) | Pass for user pass |
| –user= |
GREYCAT_USER=(null) | Impersonate mode to serve or run using a user name |
| –tz= |
GREYCAT_TZ=(null) | Configure local timezone (see https://www.iana.org/time-zones, ex: Europe/Luxembourg) |
| –validity= |
GREYCAT_VALIDITY=1day | Validity of connection cookie |
| –unsecure | GREYCAT_UNSECURE=false | Allows GreyCat tokens to be used behind an unsecure reverse-proxy (aka http) |
| –task_pool_capacity= |
GREYCAT_TASK_POOL_CAPACITY=10000 | Maximum number of tasks in the queue |
| –request_pool_capacity= |
GREYCAT_REQUEST_POOL_CAPACITY=8192 | Maximum number of connections served at once (a kept-alive connection holds a slot while idle) |
| –mode= |
GREYCAT_MODE=(null) | Default mode (serve,run) |
| –keep_alive | GREYCAT_KEEP_ALIVE=true | Let clients reuse a connection across requests (Connection: keep-alive) |
| –backup_path= |
GREYCAT_BACKUP_PATH=backup | Path to store and retrieve backups |
| –max_backup_files= |
GREYCAT_MAX_BACKUP_FILES=3 | Maximum number of backup files to keep in backup_path |
| –defrag_ratio= |
GREYCAT_DEFRAG_RATIO=2.00 | Blocks held per live block tolerated across data files before defrag (2.0 = half garbage) (must be > 1.0, a value <= 0 deactivates defrag) |
| –request_ttl= |
GREYCAT_REQUEST_TTL=20s | Max HTTP request lifetime. An RPC call still queued or running is cancelled, an idle connection is closed |
| –ca_path= |
GREYCAT_CA_PATH=(null) | Directory containing custom CA certificates to trust for SSL/TLS connections |
| –mcp_content= |
GREYCAT_MCP_CONTENT=both | How MCP tools/call ships its payload: duplicated, structuredContent only, or content text only (both,structured,text) |
| –mcp_instructions= |
GREYCAT_MCP_INSTRUCTIONS=(null) | Usage guidance returned to MCP clients in the initialize result |
| –openapi | GREYCAT_OPENAPI=true | Expose every @expose’d function in the OpenAPI v3 spec. When false, only @tag(“openapi”) ones are |
| –max_sse= |
GREYCAT_MAX_SSE=2048 | Maximum number of open task event streams (GET /runtime::Task::events). Each holds a request pool slot |
| –max_sse_per_user= |
GREYCAT_MAX_SSE_PER_USER=16 | Maximum number of open task event streams per user |
| –max_args_memory= |
GREYCAT_MAX_ARGS_MEMORY=1.05MB | RPC arguments larger than this are streamed to the task’s arguments file instead of held in memory (if no suffix, default is MiB) |
| –metrics= |
GREYCAT_METRICS=(null) | Metrics recorded, each to its own stream: host (host_metrics, HostMetric every --metrics_host_step), task (task_metrics, TaskMetric per task), http (http_metrics, HttpMetric per HTTP request). None when unset (comma-separated: host,task,http) |
| –metrics_http_fields= |
GREYCAT_METRICS_HTTP_FIELDS=(null) | Personal data the HttpMetric records, when the http metric is on (GREYCAT_METRICS): ip (client address), forwarded_for (X-Forwarded-For header), user_agent (User-Agent header). None when unset (comma-separated: ip,forwarded_for,user_agent) |
| –metrics_http_flush_size= |
GREYCAT_METRICS_HTTP_FLUSH_SIZE=64.0KB | HttpMetric records are buffered and written to http_metrics once they reach this size, 0 writes each one at once (if no suffix, default is MiB) |
| –metrics_http_flush_step= |
GREYCAT_METRICS_HTTP_FLUSH_STEP=1s | Longest time an HttpMetric record stays buffered before it is written to http_metrics |
| –log_flush_size= |
GREYCAT_LOG_FLUSH_SIZE=64.0KB | Log records are buffered and written to the log stream once they reach this size, 0 writes each one at once (if no suffix, default is MiB) |
| –log_flush_step= |
GREYCAT_LOG_FLUSH_STEP=1s | Longest time a log record stays buffered before it is written to the log stream |
| –metrics_host_flush_size= |
GREYCAT_METRICS_HOST_FLUSH_SIZE=64.0KB | HostMetric records are buffered and written to host_metrics once they reach this size, 0 writes each one at once (if no suffix, default is MiB) |
| –metrics_host_flush_step= |
GREYCAT_METRICS_HOST_FLUSH_STEP=1s | Longest time a HostMetric record stays buffered before it is written to host_metrics |
| –metrics_task_flush_size= |
GREYCAT_METRICS_TASK_FLUSH_SIZE=64.0KB | TaskMetric records are buffered and written to task_metrics once they reach this size, 0 writes each one at once (if no suffix, default is MiB) |
| –metrics_task_flush_step= |
GREYCAT_METRICS_TASK_FLUSH_STEP=1s | Longest time a TaskMetric record stays buffered before it is written to task_metrics |
| –log_flush_on_error | GREYCAT_LOG_FLUSH_ON_ERROR=false | An error record writes the buffered log records to the log stream at once |
Runtime info
The runtime module provides a RuntimeInfo object, returned by Runtime::info(), which contains all important information about the currently running GreyCat server
| Name | Type | Description |
|---|---|---|
| version | String | GreyCat version |
| program_version | String? | |
| arch | String | |
| timezone | TimeZone | env specified tz else machine tz |
| license | License | |
| io_threads | int | |
| mem_total | int | Cache size (--cache) |
| mem_workers | int | Part of the cache shared by the task workers |
| small | RuntimeInfoClass | Task workers of the small class, which run RPC calls |
| medium | RuntimeInfoClass | Task workers of the medium class |
| large | RuntimeInfoClass | Task workers of the large class |
| disk_data_bytes | int |
Runtime Info Class
| Name | Type | Description |
|---|---|---|
| workers | int | Workers of the class, 0 when its tasks run in the nearest class that has workers |
| mem_worker | int | Object cache budget of one worker of the class, in bytes |
| cache_ratio | float | Cache of one worker relative to a medium one (--cache_ratio_small, 1, --cache_ratio_large) |
Store Stats
Runtime::store_stats() returns a StoreStats object describing the store. It reads every live block, so it lasts as long as a full backup.
| Name | Type | Description |
|---|---|---|
| live_blocks | int | Blocks reachable from the store index and readable |
| live_bytes | int | Payload bytes those blocks hold |
| file_bytes | int | Bytes the zone files occupy on disk, fragmentation included |
| abi_bytes | int | Bytes of the ABI file |
| meta_bytes | int | Bytes the block index occupies |
| types | Array |
Live blocks by type, the largest share of live_bytes first |
| damaged | Array |
Blocks the index lists but that would not read |
| unreadable_zones | Array |
Zones that could not be opened |
| worlds | Array |
The worlds, in the order World::list gives them |