This is the guided start: you create a folder, paste four small files, and end up stepping through your first Mica program in a real debugger — variables in the panel, breakpoints on source lines. It takes about fifteen minutes, works the same on macOS, Linux, and Windows, and installs nothing on your machine beyond Docker and VS Code.

The short way. Everything on this page also exists ready-made: git clone https://gitlab.com/mica-lang/mica-container.git, open the folder in VS Code, choose Reopen in Container, and you have the container, all the example suite, the benchmarks and F5 debugging over every one of them. That repository is the starter for Mica and the home of this tutorial series.

This page is the long way, and it is worth the fifteen minutes once: you build the setup by hand, so you know what each piece does rather than inheriting it.

What you need — once

  1. Docker Desktop (macOS, Windows) or Docker Engine (Linux), running.
  2. VS Code.
  3. In VS Code, the Dev Containers extension — open the Extensions view, search Dev Containers, install the one by Microsoft (ms-vscode-remote.remote-containers).

That is the only extension you install yourself. The Mica language extension and the debugger extension arrive automatically in a moment — the container configuration you are about to paste names them, and VS Code installs them inside the container for you.

Step 1 — an empty folder

In a terminal:

mkdir hello-mica && cd hello-mica
mkdir .devcontainer .vscode
code .

The two dot-folders are where VS Code looks for its configuration — the container description goes into .devcontainer, the build-and-debug wiring into .vscode.

(If code is not on your PATH: open VS Code, press F1, run Shell Command: Install ‘code’ command in PATH — or simply open the folder via File → Open Folder.)

Step 2 — describe the container

In VS Code’s Explorer, create a file devcontainer.json inside the .devcontainer folder, with exactly this content:

{
  "name": "Mica",
  "image": "micalang/mica:latest",
  "customizations": {
    "vscode": {
      "extensions": [
        "mica-development-ug.mica-language",
        "ms-vscode.cpptools"
      ]
    }
  },
  "runArgs": ["--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"],
  "containerEnv": { "DEBUGINFOD_URLS": "" },
  "remoteUser": "mica"
}

Four facts in one file: which image to run (the official Mica image — compiler, linker tools, and gdb, about 77 MB, for Intel and ARM machines alike), which two extensions to install inside it, and debugger-friendly container settings — including switching off gdb’s online symbol lookup, which would otherwise freeze containerized debug sessions for minutes.

Step 3 — wire the debugger

Two more small files teach VS Code how to build and debug the file you are editing. Create .vscode/tasks.json:

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Mica: build current file (debug)",
      "type": "shell",
      "command": "mica-build-debug",
      "args": ["${file}"],
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "problemMatcher": []
    }
  ]
}

and .vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug current Mica binary",
      "type": "cppdbg",
      "request": "launch",
      "program": "${workspaceFolder}/build/${fileBasenameNoExtension}/${fileBasenameNoExtension}",
      "args": [],
      "stopAtEntry": true,
      "preLaunchTask": "Mica: build current file (debug)",
      "cwd": "${workspaceFolder}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "miDebuggerPath": "/usr/bin/gdb",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        },
        {
          "description": "Set disassembly flavor to Intel",
          "text": "-gdb-set disassembly-flavor intel",
          "ignoreFailures": true
        }
      ],
      "internalConsoleOptions": "openOnSessionStart"
    }
  ]
}

The task compiles whatever .mica file you have open, at the debug tier — every variable observable, every line breakable. The launch configuration runs the result under gdb. (Both files, and everything else on this page, also live ready-made in the tutorial repository.)

Step 4 — your first program

Create Hello.mica:

program Hello;

imp
    WriteLn : std;

begin
    WriteLn("Hello, Mica!");
end.

Two things worth noticing already. program Hello; names the program — the compiled binary will be named Hello after this declaration, and by convention the file carries the same name. And WriteLn is imported: in Mica everything a program uses arrives through an imp declaration, so a source file tells you its dependencies honestly — nothing is ambient.

Step 5 — reopen in the container

VS Code has noticed the .devcontainer folder and offers Reopen in Container in the corner — click it (or press F1 and run Dev Containers: Reopen in Container).

The first time, this pulls the image and installs the two extensions into it — a minute or two. Every later open is seconds. When the window reloads you are inside the container: the Mica extension is active, and hovering WriteLn shows its signature — that answer comes from the compiler itself, running as a language server.

Step 6 — compile it

Open a terminal (Terminal → New Terminal — it is a shell inside the container) and:

mica-build-debug Hello.mica

Everything the build produces lands in a folder named after the source file: build/Hello/. There is a sibling, mica-build-fullopt, that produces the fully optimized build with the same usage — but for the debugger, the debug tier is the one you want.

Step 7 — run it

./build/Hello/Hello
Hello, Mica!

Two namings meet here: the folder is named after the file, the binary after the program declaration in the source — and by Mica convention the two agree, which is why the file is called Hello.mica. Rename the program, and the binary renames with it: the source is in charge.

Step 8 — something worth debugging

Replace the content of Hello.mica with:

program Hello;

imp
    WriteLn : std;

var
    greeting: string;
    answer: int64;

begin
    greeting := "Hello, Mica!";
    answer := 6 * 7;
    WriteLn("%ls says the answer is %lld", greeting, answer);
end.

var declares variables with explicit types; := assigns. The format string is checked at compile time: %ls is a string, %lld an int64. Try changing %lld to %d and saving — the editor underlines it immediately with the compiler’s own error (format specifier ‘%d’ incompatible with type: int64), because the language server runs the same analysis the build does. Change it back.

Step 9 — breakpoint, inspect, step

  1. Make sure Hello.mica is the active editor tab — the debugger builds and runs whatever source file you have focused, so debugging always starts from the program you are looking at. Then click in the gutter left of the WriteLn line — a red breakpoint dot appears.
  2. Press F5. The build task compiles the focused file — Hello.mica — and gdb launches its binary, pausing at the program’s entry — that first stop is deliberate, so you always get control before anything runs. (The Debug Console fills with startup chatter — gdb’s version banner, a Failed to set controlling terminal warning, on ARM machines an assuming x86_64 guess from the VS Code extension. All of it is harmless and none of it is Mica: the pause at entry and the Variables panel are the debugger working.)
  3. Press F5 again to continue to your breakpoint. Look at the Variables panel: greeting is there with its text and its length of 12 runes, answer is 42, and exit — the program’s result variable — is 0.
  4. Press F10 to step over the WriteLn line. The Debug Console shows Hello, Mica! says the answer is 42.
  5. Press F5 to let the program finish.

You have compiled, run, and stepped through native ARM64 or x86-64 machine code — whichever your machine speaks — with full source-level debugging, and nothing was installed on your computer beyond Docker and VS Code.

Where to go next

Mica as a scripting language is the five-minute stop worth making before the series proper: one command compiles and runs a file, a shebang line turns it into a tool on your PATH, and every compile-time check runs before the program does. It changes how you use everything that follows.

Part 2: The shape of a Mica program reads that program properly — the four parts every Mica program has, why every name must be imported, and the format string the compiler checks before it builds anything. It works from the cloned repository, so git clone https://gitlab.com/mica-lang/mica-container.git is the one command that carries you into the rest of the series.

Meanwhile:

Stuck, or delighted? info@mica-dev.com reads everything.