Skip to content

Coders CLI

Coders is a transpiler that generates native code for multiple platforms from a single DSL (.jssp). It uses platform prompts to map declared resources (such as controller, mapper, message, error) into 1:1 target outputs, so the same DSL can expand across languages and frameworks.

For setup, see Quick Start and What is Coders?.

Configuration notes

config.yml controls the CLI end to end.

  • entry: root .jssp file to parse by default.
  • projects: each item defines platform, name, outPath, entry, target, language, and options. In options you can set fields such as package, namespace, module, mainClass, languageVersion, version, group, description, plugins, dependencies, onlySource, extra, and useHistory to suit the platform needs.
  • llmOptions: configure provider (provider), model (model), endpoint (url), auth (apiKey), timeout (timeoutSeconds), and streaming (stream). Add any extra fields required by your provider in the same block.

Coders DSL Overview

Coders DSL is composed of:

  • declarations: domain, table, entity, mapper, struct, class, controller, api, define
  • execution: func, main, @prompt
  • resources: message, error, property, css
  • UI: html + <template>

Each declaration is converted into platform-specific files by the prompts. Core syntax is covered in the Syntax page.

Data Modeling

Domain

js
domain Url string(512);
domain Name string(32);

Table

js
table user {
  user_id int64 auto;
  name Name;
  create_at datetime = now();
  key(user_id);
  index(create_at);
  unique index(name);
}

Data

js
data user(name) {
  ('user1');
  ('user2');
}

Entity

js
entity UserVo from @table.user {}

entity UserProfileVo {
  var userId int64;
  var name Name;
  var avatarUrl Url;
}

Mapper

js
mapper UserMapper {
  query insertUser(name Name) int32 {
    insert user(name)
    values(:name);
  }

  query updateUser(userId int64, name Name) int32 {
    update user set name = :name
    where user_id = :userId;
  }
}

DB Procedure / Function

js
dbproc sample(userId string(10), out name string(100)) {
  var _name string(100);
  var c cursor = select name into _name from user_id = userId;
  c.open();
  c.fetch();
  name = _name;
  c.close();
}

dbfunc countUser() int32 {
  var _count int32;
  select count(*) into _count from user;
  return _count;
}

Application Structure

Struct / Class / Interface

js
struct SignupRequest {
  var email string;
  var password string;
}

abstract class BaseSample {
  func hello() void;
}

class Sample extends BaseSample {
  var name string;

  constructor(name string) {
    this.name = name;
  }

  func hello() void {
    @console.log("hello");
  }
}
js
[alias='console']
interface Console {
  static func log(message string) void;
  static func error(message string) void;
  static func warn(message string) void;
}

Enum

js
define enum Status {
  READY 1,
  RUNNING 2,
  DONE 3
}

API and Services

Controller

js
[baseUrl='/api/v1', comment='User controller']
controller UserController {
  [method=post, route='/signup']
  func signup(@body req SignupRequest) SignupResponse {
    var res = SignupResponse();
    var n = @mapper.UserMapper.insertUser(req.email, req.password);
    if (n <= 0) {
      res.code = AppErrors.failed.code;
      res.message = AppErrors.failed.message;
      return res;
    }
    res.code = AppErrors.success.code;
    return res;
  }
}

Api (Client)

js
[comment='User API']
api UserApi from @controller.UserController {}

Frontend targets (React/Vue/Svelte) and Flutter widgets

The Coders DSL html class is converted into frontend components. The same DSL maps to React, Vue, or Svelte components depending on the platform. Flutter uses the widget class, which is generated as widgets.

Common concepts

  • ref var -> component state
  • @model -> input binding
  • @click -> event handler
  • define css -> style tokens
  • @api -> controller-based API calls

Example: login screen DSL

js
define css {
  text.primary {
    text-gray-800
  }
}

html LoginPage {
  ref var nickname string = "";
  ref var password string = "";

  func login() {
    var res = @api.login(nickname, password);
    @console.log(res.code);
  }

  // Define UI in the template block.
}

React mapping concepts

  • ref var -> useState
  • @model -> value + onChange
  • @click -> onClick
  • define css -> class/style token mapping

Vue/Svelte mapping concepts

  • ref var -> reactive state
  • @model -> v-model or bind:value
  • @click -> @click/on:click

Flutter widgets

Flutter uses the widget class instead of html.

js
widget LoginPage {
  ref var nickname string = "";
  ref var password string = "";

  func login() {
    var res = @api.login(nickname, password);
    @console.log(res.code);
  }

  // Define UI in the widget layout block.
}

Flutter mapping concepts

  • ref var -> State + setState
  • @model -> TextEditingController/OnChanged
  • @click -> onPressed

The output structure varies by platform, but html/widget declarations are always converted into components/widgets.

Resource Definitions

Property

js
define property app {
  baseUrl = "https://api.example.com";
}

define property [profile='dev'] app {
  baseUrl = "https://dev.api.example.com";
}

Message + Message Class

js
define message[locale='en'] app {
  hello: "Hello"
  welcome: "Welcome {name}"
}

message MessageApp from @message.app {
  static func setLocale(locale string) void;
  static var hello string;
  static func welcome(name string) string;
}

Error + Error Class

js
define error[locale='en'] app {
  not_found (100) = "Resource not found"
  server_error (200) = "Internal server error"
}

error AppErrors from @error.app {}

CSS + HTML

js
define css {
  text.primary {
    text-gray-800 dark:text-gray-100
  }
}

html LoginPage {
  ref var nickname string = "";
  ref var password string = "";

  func login() {
    var res = @api.login(nickname, password);
    @console.log(res.code);
  }

  template {
    div class="@css.text.primary" {
      input @model="nickname";
      input @model="password";
      button @click="login" { "Login" }
    }
  }
}

@prompt Directives

@prompt is a hint for native code patterns that do not exist in the DSL. The LLM translates the instruction into platform-specific code.

js
func main() {
  @prompt `"Hello, World!" output`
}

@prompt Conversion Example (Rust/Go/Java)

js
func main(args list<string>) {
  @prompt `Implement the Sieve of Eratosthenes to print primes up to args[0]`
}
rust
use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    let n: usize = args.get(1).unwrap_or(&"0".to_string()).parse().unwrap_or(0);
    if n < 2 {
        return;
    }
    let mut is_prime = vec![true; n + 1];
    is_prime[0] = false;
    if n >= 1 {
        is_prime[1] = false;
    }
    let mut p = 2;
    while p * p <= n {
        if is_prime[p] {
            let mut multiple = p * p;
            while multiple <= n {
                is_prime[multiple] = false;
                multiple += p;
            }
        }
        p += 1;
    }
    for i in 2..=n {
        if is_prime[i] {
            println!("{i}");
        }
    }
}
go
package main

import (
	"fmt"
	"os"
	"strconv"
)

func main() {
	n := 0
	if len(os.Args) > 1 {
		if v, err := strconv.Atoi(os.Args[1]); err == nil {
			n = v
		}
	}
	if n < 2 {
		return
	}
	isPrime := make([]bool, n+1)
	for i := range isPrime {
		isPrime[i] = true
	}
	isPrime[0] = false
	if n >= 1 {
		isPrime[1] = false
	}
	for p := 2; p*p <= n; p++ {
		if isPrime[p] {
			for m := p * p; m <= n; m += p {
				isPrime[m] = false
			}
		}
	}
	for i := 2; i <= n; i++ {
		if isPrime[i] {
			fmt.Println(i)
		}
	}
}
java
public class Main {
    public static void main(String[] args) {
        int n = 0;
        if (args.length > 0) {
            try {
                n = Integer.parseInt(args[0]);
            } catch (NumberFormatException ignored) {
                n = 0;
            }
        }
        if (n < 2) {
            return;
        }
        boolean[] isPrime = new boolean[n + 1];
        for (int i = 0; i <= n; i++) {
            isPrime[i] = true;
        }
        isPrime[0] = false;
        if (n >= 1) {
            isPrime[1] = false;
        }
        for (int p = 2; p * p <= n; p++) {
            if (isPrime[p]) {
                for (int m = p * p; m <= n; m += p) {
                    isPrime[m] = false;
                }
            }
        }
        for (int i = 2; i <= n; i++) {
            if (isPrime[i]) {
                System.out.println(i);
            }
        }
    }
}

Bash/PowerShell prompts

The shell keyword is converted into script functions. The Bash/PowerShell platforms include a runner (main or invocation code) so the shell functions actually execute.

Bash conversion rules

  • Include set -euo pipefail at the top of the script.
  • shell functions are converted into Bash functions.
  • For shell identifier(), lower_snake_case is recommended.
dsl
shell download_file(url string, dest string) {
  @prompt `Download a file with curl`
}
bash
set -euo pipefail

download_file() {
  local url="$1"
  local dest="$2"
  curl -fsSL "$url" -o "$dest"
}

main() {
  download_file "$@"
}

main "$@"

PowerShell conversion rules

  • shell functions are converted into PowerShell function.
  • For shell identifier(), Verb-Noun PascalCase is recommended.
  • Include main or direct invocation code for execution.
dsl
shell download_file(url string, dest string) {
  @prompt `Download a file with Invoke-WebRequest`
}
powershell
function Download-File {
  param (
    [Parameter(Mandatory = $true)]
    [string]$Url,

    [Parameter(Mandatory = $true)]
    [string]$Dest
  )

  Invoke-WebRequest -Uri $Url -OutFile $Dest
}

Download-File -Url $Url -Dest $Dest

Conversion Overview

Coders splits DSL declarations into resource units, then renders files using platform templates.

  • Analyze declarations (controller, mapper, html/widget)
  • Generate resource-level code skeletons
  • Expand @prompt instructions into native code

End-to-End Example

js
domain Email string(320);
domain Password string(128);

struct SignupRequest {
  var email Email;
  var password Password;
}

struct SignupResponse {
  var code int32;
  var message string;
}

table user {
  user_id int64 auto;
  email Email unique;
  password Password;
  key(user_id);
}

mapper UserMapper {
  query insertUser(email Email, password Password) int32 {
    insert user(email, password)
    values (:email, :password);
  }
}

define error[locale='en'] app {
  success (0) = "OK"
  failed (100) = "Failed"
}

error AppErrors from @error.app {}

[baseUrl='/api/v1']
controller UserController {
  [method=post, route='/signup']
  func signup(@body req SignupRequest) SignupResponse {
    var res = SignupResponse();
    var n = @mapper.UserMapper.insertUser(req.email, req.password);
    if (n <= 0) {
      res.code = AppErrors.failed.code;
      res.message = AppErrors.failed.message;
      return res;
    }
    res.code = AppErrors.success.code;
    res.message = AppErrors.success.message;
    return res;
  }
}