Skip to content

dimiro1/lunar

Repository files navigation

Lunar Logo

Lunar (formerly Faas-Go)

Go Reference Go Report Card

A lightweight, self-hosted Function-as-a-Service platform written in Go with Lua scripting.

Beta Phase Notice: This project is currently in beta. New features and changes are actively being developed, but I promise to maintain backward compatibility for all Lua APIs.

Features

  • Simple Lua Functions - Write serverless functions in Lua
  • Code Editor - Monaco Editor with autocomplete and inline documentation
  • HTTP Triggers - Execute functions via HTTP requests
  • Built-in APIs - HTTP client, KV store, environment variables, logging, and more
  • AI Integration - Chat completions with OpenAI and Anthropic, with request/response logging
  • Email Integration - Send emails via Resend with scheduling support
  • Version Control - Track and manage function versions
  • Execution History - Monitor function executions and logs
  • Beautiful Error Messages - Human-friendly error messages with code context, line numbers, and actionable suggestions
  • Web Dashboard - Manage functions through a clean web interface
  • API Documentation - Swagger UI available at /docs
  • Lightweight - Single binary, no external dependencies

Screenshots

Dashboard

Dashboard

Function Editor

Edit Function

Environment Variables

Environment Variables

Testing Functions

Test Function

Execution History

Executions

Version Management

Versions

Version Comparison

Version Comparison

Command Palette

Command Palette

Error Messages

Error Messages

AI Request Logs

AI Request Logs

Email Request Logs

Email Request Logs

Quick Start

Prerequisites

  • Go 1.26 or newer
  • make
  • Chrome or Chromium if you plan to run the E2E test suite

For CLI internals and code generation details, see cli/README.md.

Building from Source

git clone https://github.com/dimiro1/lunar.git
cd lunar
make build

Running

./build/lunar

For local development, you can also install the optional contributor tools:

make install-tools

This installs air for live reload and goreleaser for release packaging.

Then start the development server with:

make dev

The application will be available at http://localhost:3000.

First-Time Setup

On first run, Lunar will automatically generate an API key and save it to data/api_key.txt. The key will be printed in the server logs:

INFO Generated new API key key=cf31cb0cdc7811ca9cec6a3c77579b3ea28c1e4e10d6fc1061ae71788834c21b file=data/api_key.txt

When you access the dashboard, you'll be prompted to enter this API key to login. The key is also available in the data/api_key.txt file.

Your First Function

  1. Open http://localhost:3000 and log in with the API key from data/api_key.txt.
  2. Create a new function named hello-world.
  3. Paste the sample handler below and save it.
  4. Copy the function ID and invoke it:
curl http://localhost:3000/fn/<function-id>

You should get back a JSON response. After that, open the function's execution history in the dashboard to inspect logs and request details.

Writing Functions

Functions are written in Lua and must export a handler function:

function handler(ctx, event)
  -- ctx contains execution context (executionId, functionId, etc.)
  -- event contains HTTP request data (method, path, query, body, headers)
  
  log.info("Function started")
  
  return {
    statusCode = 200,
    headers = { ["Content-Type"] = "application/json" },
    body = json.encode({ message = "Hello, World!" })
  }
end

Available APIs

  • log - Logging utilities (info, debug, warn, error)
  • kv - Key-value storage (get, set, delete)
  • env - Environment variables (get)
  • http - HTTP client (get, post, put, delete)
  • json - JSON encoding/decoding
  • crypto - Cryptographic functions (md5, sha256, hmac, uuid)
  • time - Time utilities (now, format, sleep)
  • url - URL utilities (parse, encode, decode)
  • strings - String manipulation
  • random - Random generators
  • base64 - Base64 encoding/decoding
  • ai - AI chat completions (OpenAI, Anthropic)
  • email - Send emails via Resend

LLM-Assisted Development

Lunar provides an llms.txt file at /llms.txt with the complete Lua API reference, including function signatures, parameters, and code examples. You can use this with any LLM-powered coding assistant to get accurate help when writing Lunar functions.

Example: Counter Function

function handler(ctx, event)
  -- Get current count from KV store
  local count = kv.get("counter") or "0"
  local newCount = tonumber(count) + 1
  
  -- Save updated count
  kv.set("counter", tostring(newCount))
  
  log.info("Counter incremented to: " .. newCount)
  
  return {
    statusCode = 200,
    headers = { ["Content-Type"] = "application/json" },
    body = json.encode({ count = newCount })
  }
end

Example: Send Email

-- Requires RESEND_API_KEY environment variable
function handler(ctx, event)
  local data = json.decode(event.body)

  local result, err = email.send({
    from = "noreply@yourdomain.com",
    to = data.email,
    subject = "Welcome!",
    html = "<h1>Hello, " .. data.name .. "!</h1>",
    scheduled_at = time.now() + 3600  -- Optional: send in 1 hour
  })

  if err then
    return {
      statusCode = 500,
      body = json.encode({ error = err })
    }
  end

  return {
    statusCode = 200,
    headers = { ["Content-Type"] = "application/json" },
    body = json.encode({ email_id = result.id })
  }
end

Calling Functions

curl -X GET http://localhost:3000/fn/{function-id}
curl -X POST http://localhost:3000/fn/{function-id} -d '{"key":"value"}'
curl -X GET http://localhost:3000/fn/{function-id}?name=John

Deployment

Docker

# Run the latest release from Docker Hub
docker run -p 3000:3000 -v $(pwd)/data:/data dimiro1/lunar:latest

# Build and run with Docker
docker build -t lunar .
docker run -p 3000:3000 -v lunar-data:/app/data lunar

# Or use Docker Compose
docker compose up -d

Railway

Lunar is ready to deploy on Railway:

  1. Connect Repository - Link your GitHub repository to Railway
  2. Add Volume - Create a volume and mount it to /data
  3. Set Environment Variables:
    • BASE_URL - Your Railway public URL (e.g., https://yourapp.up.railway.app)
    • API_KEY - (Optional) Set a custom API key, or let it auto-generate
  4. Deploy - Railway will automatically detect the Dockerfile and deploy

The Dockerfile is Railway-compatible and will:

  • Use Railway's automatic PORT environment variable
  • Bind to 0.0.0.0:$PORT for public networking
  • Persist data to the mounted volume at /data

Configuration

Lunar can be configured via environment variables:

PORT=3000                 # HTTP server port (default: 3000)
DATA_DIR=./data           # Data directory for SQLite database (default: ./data)
EXECUTION_TIMEOUT=300     # Function execution timeout in seconds (default: 300)
API_KEY=your-key-here     # API key for authentication (auto-generated if not set)
BASE_URL=http://localhost:3000  # Base URL for the deployment (auto-detected if not set)

Authentication

The dashboard requires authentication via API key. You can:

  1. Auto-generate (recommended) - Let Lunar generate a secure key on first run
  2. Set manually - Provide your own key via the API_KEY environment variable

API calls can authenticate using either:

  • Cookie - Automatically handled by the dashboard after login
  • Bearer token - Include Authorization: Bearer YOUR_API_KEY header

Example API call with Bearer token:

curl -H "Authorization: Bearer YOUR_API_KEY" http://localhost:3000/api/functions

Note: Function execution endpoints (/fn/{id}) do not require authentication.

CLI

Lunar ships a command-line client (lunar-cli) that is auto-generated from the OpenAPI spec, so it always stays in sync with the API.

Installation

go install github.com/dimiro1/lunar/lunar-cli@latest

Or download a pre-built binary from the Releases page (lunar-cli_* archives).

AI Agent Skills

AI agent skills require the CLI to be installed first.

Lunar ships built-in skill definitions that teach your AI coding agent how to use the CLI and write Lua functions.

lunar-cli skills list             # show available skills
lunar-cli skills show lunar-cli   # CLI command reference
lunar-cli skills show lunar-lua   # Lua function authoring guide

To install them, ask your agent:

"Install the Lunar skills from the lunar-cli skills command."

Authentication

# Start the device authorization flow (opens a browser tab for approval)
lunar-cli --server http://your-lunar-server login

# If the browser does not open automatically, use the printed approval URL and code.

# The token is saved to ~/.config/lunar/config.yaml automatically
# To log out and clear the stored token:
lunar-cli logout

You can also skip the login flow and pass a token directly:

lunar-cli --token YOUR_API_KEY functions list

# Or via environment variable:
export LUNAR_SERVER=http://your-lunar-server
export LUNAR_TOKEN=YOUR_API_KEY
lunar-cli functions list

Configuration

The CLI stores its configuration in ~/.config/lunar/config.yaml:

server: http://localhost:3000
token: <your-api-token>

Flags and environment variables always take precedence over the config file:

Priority Source
1 (highest) --server / --token flags
2 LUNAR_SERVER / LUNAR_TOKEN env vars
3 ~/.config/lunar/config.yaml

Commands

Functions

lunar-cli functions list [--limit 20] [--offset 0]
lunar-cli functions create --name hello-world --code handler.lua
lunar-cli functions create --name hello-world --code -  # read code from stdin
lunar-cli functions get <id>
lunar-cli functions update <id> --name new-name
lunar-cli functions update <id> --cron-schedule "*/5 * * * *" --cron-status active
lunar-cli functions update <id> --disabled
lunar-cli functions delete <id>
lunar-cli functions env <id> --env API_KEY=secret --env DEBUG=true
lunar-cli functions kv <id> --kv counter=0 --kv state=idle
lunar-cli functions kv <id> --kv shared=value --global   # write to global KV
lunar-cli functions next-run <id>

Versions

lunar-cli versions list <function-id>
lunar-cli versions get <function-id> <version-number>
lunar-cli versions activate <function-id> <version-id>
lunar-cli versions delete <function-id> <version-id>
lunar-cli versions diff <function-id> <v1> <v2>

Executions

lunar-cli executions list <function-id>
lunar-cli executions get <execution-id>
lunar-cli executions logs <execution-id>
lunar-cli executions ai-requests <execution-id>
lunar-cli executions email-requests <execution-id>

API Tokens

lunar-cli tokens list
lunar-cli tokens revoke <token-id>

LLM Reference

lunar-cli llms

Invoke

Execute a function directly without authentication (functions are public by default):

lunar-cli invoke <function-id>
lunar-cli invoke <function-id> --method POST --body '{"key":"value"}'
lunar-cli invoke <function-id> --method POST --body -   # read body from stdin

Keeping the CLI in Sync with the API

The CLI commands are auto-generated from internal/api/docs/openapi.yaml. When the API changes, regenerate with:

cd cli
go generate ./...
go build ./...

Testing

Go Tests

Run the Go unit tests:

make test

Frontend Tests (Jasmine)

The frontend uses Jasmine for unit testing, running directly in the browser without Node.js dependencies.

make test-frontend

This starts a local Go server and opens the test runner at http://localhost:8888/test/SpecRunner.html. Tests cover:

  • Route URL generators
  • UI components (Button, Badge, Table, Pagination, ...)

E2E Tests (chromedp)

End-to-end tests use chromedp to run a headless Chrome browser:

Make sure Chrome or Chromium is installed before running them.

make test-e2e

E2E tests cover:

  • Login flow
  • Page navigation
  • Functions list rendering

Run All Tests

make test-all

This runs Go unit tests and E2E tests. Run make test-frontend separately to open the browser-based Jasmine tests.

Architecture

  • Backend - Go with standard library HTTP server, SQLite database
  • Frontend - Mithril.js SPA with Monaco Editor
  • Runtime - GopherLua for Lua script execution
  • Storage - SQLite for functions, versions, executions, KV store, and environment variables

Frontend Dependencies

JavaScript dependencies are vendored in frontend/vendor/ (no npm required). Versions are managed in the Makefile:

Library Purpose
Mithril.js SPA framework
Monaco Editor Code editor
Highlight.js Syntax highlighting
Jasmine Frontend testing

To update dependencies, edit the version variables in the Makefile and run:

make vendor-js

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

Author

Claudemiro Alves Feitosa Neto

License

MIT License - see LICENSE file for details.

About

A lightweight, self-hosted Function-as-a-Service platform written in Go with Lua scripting.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors