Agent mode

Every minc tool can answer in records instead of terminal text. minc agent serves those records over the Model Context Protocol, giving a coding agent six tools to compile, run, test, debug, profile and query a project.

The server keeps the source index warm between calls. Answers about the code come from the parser's index of resolved names. A crash comes back as a symbolized backtrace.

Setup

With Claude Code:

claude mcp add minc -- minc agent

With any other client that can launch a stdio server:

{
  "mcpServers": {
    "minc": { "command": "minc", "args": ["agent"] }
  }
}

One registration covers every project. If the client offers the MCP roots capability, the server works in the client's first root and follows it when it changes. Otherwise it works in the directory it started in. Pass --root <dir> to pin it.

The install puts minc, minc-lsp and minc-dbg side by side. The server itself runs inside minc-lsp, and the debug and profile tools call minc-dbg.

The tools

toolargumentsresult
querywhat, name, targetdefinitions, references, callers, matching symbols, defining files, import closure
compilefile, output, flags, hashdiagnostics with codes and fixes, then a summary or output record
runfile, args, timeout, memory, flagsthe program's output, then exit status, milliseconds, peak memory
debugfile, argsthe fault and a symbolized backtrace
profilefile, args, secondsthe functions by share of samples
testscope, flagsone record per test, then the results

A tool sets isError when its command exits nonzero. For compile that means diagnostics. For run it means the program failed or crashed. compile, run, debug and profile work on the file you name. test runs the whole project suite, through build.mc if the project has one.

Diagnostics carry the repair

When the compiler knows the mechanical repair, it ships the fix with the diagnostic, so the agent can apply it directly.

{"kind":"error","file":"app.mc","line":5,"col":9,"code":"type-mismatch",
 "message":"initializer type mismatch",
 "fix":{"kind":"wrap","line":5,"col":13,"end_col":16,"before":"cast(i32, ","after":")"}}
codefixeffect
type-mismatch, sign-mismatchwrapput before and after around the expression at line:col
must-useinsertput text at line:col, here ignore 
unused-variable, unreachabledelete_lineremove the line
syntaxreported with position and message

What comes back

Each tool returns one text block holding one JSON object per line, the same records the command line prints under --agent=json.

recordfromfields
error, warning, noteevery toolfile, line, col, code, message, fix
summary, outputcompileerrors; or file, bytes, lines
hashcompilethe output's SHA-256; the same source and flags give the same digest
runrun, debugexit, ms, peak_kb, and signal, timeout or status on a failure
crashdebugsignal, pc, frames of fn, file, line
profileprofilesamples, ms, exit, functions of fn, samples, pct
test, resultstestname, status, ms, exit, a failure's output or diagnostics; then passed, failed, unchanged
leak--track-alloc buildslive, total allocations at exit
def, ref, caller, symbol, filequeryfile, line, col, symbol; node on definitions, in on references, caller and sites on callers, of when a name has more than one definition

A crash record names the faulting instruction and the path that reached it. Inlined functions appear under their caller, each with its own line:

{"kind":"crash","signal":"access_violation","pc":"0x401042",
 "frames":[{"fn":"depth","file":"rec.mc","line":2},{"fn":"depth","file":"rec.mc","line":3},
           {"fn":"main","file":"rec.mc","line":7}]}
{"kind":"run","exit":-1073741819,"status":"0xc0000005"}

The profiler samples the instruction pointer about a thousand times a second and ranks the functions by share:

{"kind":"profile","samples":1095,"ms":1674,"exit":0,
 "functions":[{"fn":"quick_sort","samples":867,"pct":79.1},
              {"fn":"insertion_sort","samples":201,"pct":18.3},
              {"fn":"main","samples":27,"pct":2.4}]}

The source index

The index records the identifiers the parser resolved to a declaration, so query reports the sites that reach it.

whatanswers
defwhere a name is defined; Struct.field names a field
refsevery reference site, with the declaration holding it
callersfunctions whose bodies reference it, with site counts
symbolsdefinitions whose name contains the text
definesthe files that define it
closureevery file a compile of the named file reads
$ minc query callers random_quat
sample_browser/sample_collision.mc:133:6   caller  query_spawn_once      1
sample_browser/sample_collision.mc:321:6   caller  create_wave_pile      1
sample_browser/sample_compound.mc:113:6    caller  build_compound_hulls  1
sample_browser/sample_joint.mc:1826:6      caller  gl_create_debris      1

The index covers top-level declarations across the tree, plus the modules it imports from outside, standard library included. It indexes for one target at a time, and target picks which when arms it keeps. It skips whatever the root's .gitignore lists, the build directory, and any directory starting with a dot. The minc compiler's own source, 153,000 lines across 51 files, indexes from cold in about 0.3 seconds. Later calls only re-index the files whose modification time or size changed.

On the command line

Each MCP tool is also a verb on the minc command line. A harness that runs shell commands instead of MCP gets the same records.

switchshape
--agentone line per diagnostic, one summary line per run, sorted output, no prompts
--agent=jsonthe same as JSON records, one JSON object per line
MINC_AGENT=1, MINC_AGENT=jsonagent mode flag for the process
$ minc app.mc --agent
app.mc:5:9: error: initializer type mismatch [fix: wrap 5:13-16 in cast(i32, ...)]
1 error(s) found

Color and source excerpts switch off by themselves when stderr is a pipe or a file. NO_COLOR switches off the color alone. The --agent flag also sets MINC_AGENT for every process the compiler starts, so compiles started by a build.mc, the test runner and the program minc run launches all inherit it.

The same tools by hand

commanddoes
minc app.mccompile; --hash prints the output's SHA-256
minc run app.mcbuild and run, with --timeout N and --memory N limits
minc debug --batch app.mcrun to the end and report a crash with its backtrace
minc profile app.mcsample the run and list the functions by share
minc testcompile and run test/*.mc; --filter, --changed, --timeout
minc query refs nameask the index
minc agentserve all of it over MCP

The profiler prints the program's own output first, then the sample count and the functions by share. Output from the headless box3d benchmark:

$ minc profile live-demo/box3d_bench.mc
samples: 118
 35.5%      42  b3SolveContacts_Convex
 13.5%      16  b3CollideTask
  6.7%       8  b3IntegrateVelocitiesTask
  5.9%       7  b3PrepareContacts_Convex
  5.0%       6  b3FinalizeBodiesTask
  5.0%       6  <outside .text>
  4.2%       5  b3WarmStartContacts_Convex
  2.5%       3  b3ScatterBodies

The --track-alloc flag builds the program with allocation counters and reports what is still live when main returns, so run tells you whether a program leaked with no change to its source. The report counts leaked allocations; it does not say where they were made.

$ minc run --track-alloc list.mc
sum 6
leak: 4 live of 4 allocations

$ minc run --track-alloc --agent=json list.mc
sum 6
{"kind":"leak","live":4,"total":4}
{"kind":"run","exit":0,"ms":36,"peak_kb":3644}

Before an agent writes minc, point it at AGENTS.md. Everything else is in the language reference.

Questions, bugs? Open an issue.