A contract is how a Mica program learns what a foreign library offers: its functions, their exact machine-level names, the types that cross the boundary, and how each function announces failure. The compiler consumes contracts instead of parsing C headers — the contract states the facts once, in one reviewable file, and every import resolves against it.
This page is the normative reference for the format. The guided introduction is Mica calls C; the failure-lifting discipline has its own article in error domains.
Where contracts come from, and where they are found
Three roads produce a contract file:
- You author one beside a C library you want to call — the MicaCallsC example is a full worked instance, and DebugWalk a minimal one.
- The compiler emits one when linking a Mica library with
--emit-contract: the filemica.externallands beside the archive, so another program can import the library by resolving that contract. - Some ship inside the compiler. The C standard library, POSIX, and
Linux surfaces are embedded contract sets selected by
imp ... : c,: posix,: linux— nothing on disk is consulted. The Dragon SDK’s curated contract is installed for reading at/usr/share/doc/mica-dragon-sdk/dragon-engine.json, a real contract over a real shipped archive you can open on your own machine.
A consumed contract is found beside the sources, named explicitly with
--external-contract, or listed in
mica.project. The published JSON schema ships in
the container as
reference/library_contracts.schema.json.
The file
One JSON document: a description and a list of libraries. Every name a
program imports resolves against exactly one library entry.
{
"description": "External library contracts for the MicaCallsC example",
"libraries": [
{
"name": "micacallsc",
"language": "c",
"type": "external",
"contract": { ... }
}
]
}| Field | Values | Meaning |
|---|---|---|
name | string | the namespace the import names: imp Touch : micacallsc |
language | c · mica | which side of the boundary the library was written on — it decides calling and failure semantics |
type | external · system · internal | external links an archive the link block names; system names an external system library; internal marks a surface embedded in the compiler — you author external, and system where the linker should find the library itself |
import_protected | boolean | when true, the library’s names are protected only at their import site — other units stay free to declare the same names for their own containers. The class a vocabulary unit wants: the bits unit’s Count beside the maps unit’s Count. The standard library carries this class, so a program may declare Length or Capacity for itself and reach the library’s own entry through the namespace it imported, std.Length(values); importing the entry and declaring the name in one unit is what the import site refuses |
version | string | the library’s version, as Semantic Versioning writes it: "2.0.0". A contract the compiler emits carries the version the library’s mica.project states, and every program built against the library names it in its build and its manifest. Optional; two contracts stating two versions of one library are refused |
interface | string | the digest of the library’s interface, sixty-four hexadecimal digits a Mica library’s build writes into the contract it emits and into the archive’s manifest. A program’s link compares the two and refuses an archive of another build: the archive 'lib/Meter.a' is another build of the library 'Meter' than the contract the program was built against describes. An authored contract omits it |
pkg_config | object | a C library’s version as the system the program is built for holds it: {"package": "sqlite3", "minimum": "3.35.0"} names the package the system’s pkg-config knows the library by and, optionally, the oldest version the contract works with. Stated instead of version |
contract | object | the surface itself: link, types, constants, functions, generic_templates |
A C library’s version belongs to the machine the program is built for, so a
contract names the library’s package and the build asks that machine’s
pkg-config, as autoconf, meson and CMake ask it: pkg-config for the
machine’s own architecture, aarch64-linux-gnu-pkg-config or
x86_64-linux-gnu-pkg-config for a cross build. The version it answers is
the one the build names, Using library 'sqlite3' 3.46.1, the one the
manifest records and the one a project’s requires reads, and a system
below the minimum answers with the library’s name:
the C library 'sqlite3' is at version '3.31.1' on this machine, as 'pkg-config' answers for the package 'sqlite3', and its contract requires at least '3.35.0'A tool that is not installed and a package it does not know are refused by the library’s name the same way; the development files of the library for the build’s target are what the system needs.
The link block
What joins the link line when any function of this library is consumed —
stated per link profile, chosen by the
--external flag:
"link": {
"static": { "flags": ["../build/MicaCallsC/libmicacallsc.a"] },
"shared": { "flags": ["-lmicacallsc"] }
}Both profiles are required; each is a list of linker arguments, spelled exactly as they should reach the linker.
Types
Types declared here become importable Mica types, and they are the only
types that may cross the boundary by name. kind selects the shape:
kind | Declares | Carries |
|---|---|---|
record | a field sequence | fields, optional packed, optional layout |
enum | named literals | literals, base_type |
subrange | a bounded integer | base_type, lower_bound, upper_bound |
array | a fixed array | element_type, dimensions (each with index_type and both bounds) |
dynamic_array | an array of T | element_type |
set | a set over an ordinal | base_type |
bitset | a fixed-width bit set | base_type |
bitrecord | named bit fields in one carrier | bit_fields (each with bit_offset and bit_width), base_type |
alias | a second name for a type | type, the reference the name stands for; the alias resolves to that type’s own descriptor, so both names are one type and assign both ways |
opaque | a C type whose layout is the C side’s alone | nothing: no fields, variants or layout; Mica holds it only through a pointer. Optional thread_safe |
error_domain | a library’s own failure codes | literals, the codes in order; the domain the errors block’s domain names. For the status_code convention every code but the first states the C value it stands for, and the first stands for every status the domain does not list |
wide_integer | int[N] or uint[N] above 64 bits | width, optional signed |
A library compiled with --emit-contract writes its exported aliases this
way: exp Same = Inner becomes an alias over the named reference to
Inner, and exp Count = int64 an alias over the built-in, so an importer
spells the name the library declared and gets the type it declared it over.
An opaque type is C’s incomplete type, struct sqlite3;: the library
knows its layout and the contract states none. Mica never holds one by
value, only a pointer to it, and such a pointer is a handle: it names an
object the C library owns and Mica never reads. So a handle crosses into a
generator or a stream’s element as the word it is, and every activation it
is handed to holds the same object. A task or a stream placed on a process
refuses a handle, because the worker’s copy of the word names nothing there.
"thread_safe": true states that the C library allows one of its objects on
several threads at once, as sqlite does for a connection opened in its
serialized mode. Only a handle to such a type crosses into a task on a
carrier or into a stream a scheduled producer feeds, because the task runs
beside the activation that scheduled it and both hold the handle. Every
other handle stays on the thread that holds it: a generator the program
pulls takes it, and tasks share it only through a variable of the activation
that scheduled them, touched in synchronized statements, whose lock then
admits one task at a time. State thread_safe only when every function of
the contract that takes the handle is safe from several threads at once, and
never for an object whose functions answer memory another thread’s call can
free, such as the text a sqlite statement answers for a column. When one
function of an otherwise safe object answers such memory, a library keeps it
in a contract of its own that programs never consume, and reaches it only
under the lock that makes it safe: the sqlite library keeps sqlite3_errmsg
beside the connection’s mutex in sqlite3-internal.external.
Everywhere a type is referenced — a field, a parameter, a return — the
reference is an object with its own kind:
{"kind": "builtin", "name": "int32"}
{"kind": "named", "name": "ScalarPacket"}
{"kind": "pointer", "to": {"kind": "named", "name": "ScalarPacket"}}
{"kind": "const_pointer", "to": {"kind": "builtin", "name": "uint8"}}
{"kind": "borrowed_pointer", "to": {"kind": "named", "name": "Sqlite"}}
{"kind": "dynamic_array", "element": {"kind": "builtin", "name": "float64"}}
{"kind": "tracked", "element": {"kind": "builtin", "name": "float64"}}
{"kind": "c_text"}
{"kind": "void"}pointer and const_pointer differ exactly as the C qualifier does, and
the compiler holds an import to it: a const_pointer parameter cannot be
written through. A borrowed_pointer carries no ownership with it: the
cell it designates belongs to someone else — a C library’s own handle
above all — so the importing program’s ownership analysis demands no
release for it. It is how a Mica library’s borrowed pointer T result
crosses an emitted contract whole. c_text is a C function’s result alone:
the NUL-terminated UTF-8 a const char * points to, which the C side owns.
The Mica signature answers a string, and every call copies the text into
it, decoded for the program’s encoding, each ill-formed byte sequence one
replacement character and a null pointer the empty string. tracked belongs
to a Mica library alone: a tracked value, a float or
a float tensor paired with the id of its tape node, whose id crosses a call
beside the value as a word of its own, so no C signature has a place for it.
A record whose shape genuinely differs per target may
declare variants keyed by architecture (amd64, arm64) in place of the
base fields — it must state every supported architecture, so a port cannot
silently inherit the wrong layout. An emitted contract may additionally
carry layout (sizes, alignments, field offsets), and it states every
type’s fingerprint with its fingerprint_version: a digest of the type’s
shape as the library compiled it. The importing compiler computes the
digest again from the contract it reads, so a contract edited after the
compiler wrote it is refused by the type’s name. An authored contract
omits them.
Functions
{
"language_name": "InotifyInit",
"external_name_utf8": "inotify_init1",
"external_name_utf32": "",
"parameters": [
{"name": "flags", "type": {"kind": "builtin", "name": "int32"},
"passing_mode": "call_by_value"}
],
"return_type": {"kind": "builtin", "name": "int32"},
"variadic": false,
"format_string": "none",
"errors": {
"convention": "negative_errno",
"domain": "posix.OsError"
},
"description": "Create an inotify instance ...",
"interface_file": "sys/inotify.h"
}| Field | Values | Meaning |
|---|---|---|
language_name | PascalCase | the name Mica source calls |
external_name_utf8 / external_name_utf32 | symbol names | the machine-level symbol per source encoding. A function that exists for one encoding only leaves the other empty, and consuming it from the wrong encoding is a compile error |
parameters | list | each with name, type, and passing_mode — call_by_value, call_by_constant_value (the const promise on a scalar or small value, enforced on the Mica side), call_by_constant_address (the const promise on a plain aggregate wider than 16 bytes: the value arrives as one pointer into caller-owned read-only storage, so a C consumer declares the parameter const T *), fixed or call_by_result, both below |
return_type | type reference | omitted or {"kind": "void"} for none |
variadic | boolean | the C ... — a Mica-borne entry never carries it, because the language has no variadic functions |
format_string | none · write · read | declares a printf/scanf-class function, which turns on compile-time checking of the format against the variadic arguments; format_string_index is the format parameter’s zero-based position — 0 for the printf shape, 1 for fprintf, 2 for snprintf |
errors | object | see below |
abi | object | optional; its aggregate_return_mode — register or hidden_return — states how the C side returns an aggregate by value, where the two conventions differ |
blocking | boolean | optional, default false: this C entry waits on the outside world by design — the fsync class. The stamp sharpens the compiler’s boundary-under-mark warning from “may stall” to “is declared to wait”; it never rejects a call |
parks | boolean | optional, default false: the call may park the calling task on a descriptor. A parking entry’s external names must name a __mica_ parking shim — the runtime routine that tries the operation without blocking and suspends only the calling task until readiness |
heapless | boolean | optional, default false: a call never allocates or releases heap memory, so a heapless routine may call the entry. The compiler writes it for an exported Mica routine declared heapless; written by hand for a C function, it is the contract author’s promise, because no compiler sees into C code |
task | boolean | optional, default false: the entry is a Mica task. The compiler writes it for an exported task, so a program that imports the entry schedules it in a concurrent block and cannot call it |
recording | language name | optional: the hidden entry that is this routine’s recording copy. The compiler writes it for an exported Mica routine that works on tracked values, so a call inside a program’s tape window runs the copy and records the routine’s body — see routines over tracked values |
async_signal_safe | boolean | optional, default false: a call may run inside a signal handler, because the function never waits and never takes a lock. Written by hand for a C function on POSIX’s async-signal-safe list; a callback bound at a signal slot may call only C functions that carry it |
requires_flags | list | additional compiler or linker flags this one function needs on the link line |
description | string | one sentence; surfaces in editor hover |
interface_file | string | the C header documenting the function — documentation, not consumed |
Two passing modes keep a parameter out of the Mica signature:
fixedwith avalue: the contract’s own argument, a machine integer every call passes at the parameter’s position, such as the-1byte count and theSQLITE_TRANSIENTdestructorsqlite3_bind_texttakes. A value outside the parameter’s type is refused, and so is a fixed parameter in a variadic function or one that takes a callback.call_by_result: the parameter’s type is a pointer to the word the C function writes, an integer or a pointer such as a handle, and the Mica call answers that word, assqlite3_open_v2answers its connection through asqlite3 **. The call passes the address of a hidden word, zeroed before every call. The C function’s own result, its status or nothing, is what itserrorsconvention reads. Where the C library answers a resource even when the call fails and asks for it back, the parameter’srelease_on_failurenames the library’s function that releases it, and a failing call hands a non-null word to it before the failure reaches the caller.
{"name": "database", "type": {"kind": "pointer", "to": {"kind": "pointer", "to": {"kind": "named", "name": "Sqlite"}}},
"passing_mode": "call_by_result", "release_on_failure": "SqliteCloseV2"},
{"name": "vfs", "type": {"kind": "builtin", "name": "int64"}, "passing_mode": "fixed", "value": 0}Two more fields appear only in contracts the compiler writes, never in one
you author: effects on a Mica-borne entry records what the exporting
unit’s transitive effect walk proved about the body (an empty object is the
walked-and-clean statement), and intrinsic names an entry the compiler
realizes inline at each call site — the embedded standard-library surface’s
own bookkeeping.
Callback slots
A C library that takes a function pointer declares that parameter a callback slot: the parameter itself carries the void-pointer type — the pointer-sized code address is what actually crosses — and the slot beside it states everything the compiler holds a binding to:
{
"name": "visit",
"type": {"kind": "pointer", "to": {"kind": "void"}},
"passing_mode": "call_by_value",
"callback": {
"class": "during_call",
"parameters": [
{"name": "context", "type": {"kind": "pointer", "to": {"kind": "void"}},
"passing_mode": "call_by_value"},
{"name": "value", "type": {"kind": "builtin", "name": "int64"},
"passing_mode": "call_by_value"}
],
"return_type": {"kind": "builtin", "name": "int64"},
"userdata_index": 2
}
}| Field | Values | Meaning |
|---|---|---|
class | during_call · registered · signal | when the library fires the bound callback: during_call only inside the imported call itself, so the caller’s frame outlives every firing; registered stores the callback and fires it after the call returns — a class this release declares but does not yet serve; signal installs the callback as a signal handler, which the kernel runs between any two instructions, so only a heapless callback binds there — see signal handlers |
parameters / return_type | type references | the C shape a bound callback declaration must match, position for position; a slot position declared void-pointer admits any Mica pointer, which is how the callback declares the pointer to its own context record |
userdata_index | zero-based ordinal | the sibling parameter carrying the userdata pointer the library passes through unchanged; omitted when the API declares none |
The only thing that may stand at a callback slot is the name of a Mica
callback declaration — the third declared subprogram kind beside task
and generator. A callback is never called from Mica and never a value;
the library behind the slot performs every firing, and the callback’s
whole environment is the explicit context record its userdata pointer
carries plus the unit’s own root storage.
The errors block
The errors block is what turns a C failure idiom into Mica’s
failure channel: the compiler synthesizes the
check the convention describes and lifts the failure, so the caller
handles it with on fail like any Mica failure — no -1 tests in user
code, ever.
convention | The C idiom it lifts |
|---|---|
negative_errno | a negative return announces failure — most of POSIX: read, write, open, the socket family |
null_errno | a null pointer return announces failure — getcwd, the fopen class |
sentinel:<value> | a stated sentinel value announces failure — mmap’s all-ones is the classic |
status_code | the returned status is itself the reason, as sqlite’s result codes are: a status outside success fails the call with the domain’s code for it |
The first three read the reason from errno. status_code reads none: the
block states success, the statuses a call answers when it succeeded, each
the call’s plain result, and every other status fails the call with the code
whose value it is, or with the domain’s first code where no code states it.
"errors": {"convention": "status_code", "success": [100, 101], "domain": "SqliteCode"}domain names the Mica error domain the lifted code lands in
(posix.OsError above). A convention tests the value a function returns, so
a function that returns nothing cannot state one. A language: "mica" entry never carries the
block: a Mica-borne callee speaks the failure channel natively, with
nothing to lift.
Constants
{"name": "InotifyCloexec", "type": {"kind": "builtin", "name": "int32"}, "value": 524288}A constant carries name, type, and value — or values keyed per
target architecture for the rare constant whose value depends on it, or
encodings keyed utf-32 and utf-8 for the few facts that follow the
build’s string encoding, which is how std states CodeUnitBytes. Exactly
one of the three forms is present. Enum literals do not repeat here;
declaring the enum type already imports its literals.
{"name": "Pi", "type": {"kind": "builtin", "name": "float64"}, "value": 3.141592653589793,
"exact": "157079632679489661923/50000000000000000000"}A real constant written without a type, such as math’s
exp Pi = 3.14159265358979323846;, carries exact beside value: the
value as written, as a rational p/q or a bare integer, or -0 for a
negative zero. value is that value rounded to float64. A program that
imports the constant rounds exact once to the type it meets, so it reads
the value the library’s own code reads. exact stands beside value only,
and the two agree: exact rounded to the constant’s type is value. The
compiler writes the field under --emit-contract; a contract that breaks
one of these rules is refused when it loads, naming the constant.
{"name": "Row", "type": {"kind": "named", "name": "Pair"}, "value": [1.5, 2.5]}A typed array constant carries its elements’ values as a list, in index
order, under its array type, which the library exports beside it:
exp Row : Pair = (1.5, 2.5); is published with
exp Pair = array[0..1] of float64;. A program that imports Row reads it
whole or element by element, as the library’s own code does. A list of
another length is refused when the contract loads, naming the constant. A
float16 or bfloat16 constant carries its value as a number, which the
program rounds once to its type.
Mica-borne libraries: generic templates
A contract with language: "mica" may carry generic_templates — the
gen blocks of a Mica library, travelling as source because
generics instantiate in the consuming compilation.
Each entry names the template, its kind (type or function), its type
parameters with their constraints, and the imports its body needs. You do
not author these: the compiler emits them with the rest of the contract
under --emit-contract.
An exported generator travels the same way, and so does every generator or template of the library that an exported one names. Because such a body is compiled in the program that imports it, what it names must reach that program with it:
| A copied body may name | A copied body may not name |
|---|---|
| the library’s imports and its exported functions, procedures, types and constants | a private variable of the library: storage never crosses, so the body reads and writes it through a private routine |
| the library’s generators and generic templates, exported or not | a private type in the signature of an exported generator or template, because every caller names the types a signature spells |
| a private function or procedure, and a private type with its literals or error codes, which the contract lists hidden | |
| a private constant, whose text travels beside the body | |
| its own parameters and locals, a local shadowing a private name included |
A hidden entry carries "hidden": true and belongs to the library alone:
the importing compilation imports it inside the copied body and nowhere
else, and no import a program writes selects it. A private routine the body
calls keeps its code in the library’s archive, linked by its symbol, and a
private type brings the private types its own shape names.
A body that names a declaration from the right-hand column is refused when the library compiles, at the name, rather than in every program that imports it:
analyzer error 5557: the variable 'base' is private to this library, but the body of 'Counting' is compiled in every unit that imports 'Counting', where no private name of this library exists: read and write it through a private function or procedure, which crosses hidden with the body
analyzer error 5612: the type 'Fault' is private to this library, but the signature of 'Checked' is compiled in every unit that imports 'Checked', where every caller names the types it spells: export it with 'exp'An object compiled beside a program follows the same rule. An ordinary exported function is compiled in its library and may name anything there.
Routines over tracked values
A library keeps a second body of every routine it exports that works on
tracked values: the recording copy, whose body records onto the tape of the
program that calls it. The copy is a hidden entry of its own, and the
routine’s entry names it in recording:
{"language_name": "Logistic", "external_name_utf32": "Neural__Logistic",
"parameters": [{"name": "z", "passing_mode": "call_by_value",
"type": {"kind": "tracked", "element": {"kind": "builtin", "name": "float64"}}}],
"return_type": {"kind": "tracked", "element": {"kind": "builtin", "name": "float64"}},
"recording": "Logistic__tape", ...}
{"language_name": "Logistic__tape", "external_name_utf32": "Neural__Logistic__tape",
"hidden": true, ...}Outside every window a program calls the routine and computes plainly; a call inside a tape window runs the copy, which the compiler imports beside the routine’s own import, so what the routine records joins the program’s tape. A contract that names a copy without listing it is refused at that call, because the call could only record nothing:
analyzer error 5632: 'Logistic' records onto the tape through a recording copy, and library 'Neural' names the copy 'Logistic__tape' without listing it, so a call inside a window would record nothing — rebuild the library with this compiler, which publishes the copy beside the routineReading order for a new contract
Author top-down, the order the compiler resolves: the library entry and its
link block first (the import now resolves and links), then the types
the boundary needs, then functions one at a time — each one testable as
soon as it is declared — and the errors block on every fallible entry
before the function is called in anger. The
MicaCallsC worked instance
follows exactly this order, and every field this page documents appears in
it, in the compiler’s shipped contracts, or in both.