This page traces what happens between an LLM response landing in the loop and a skill actually running.
The prompt demands a tuple of up to 5 skill s-expressions:
((skillName1 "arg1") (skillName2 "arg2") ...)
With the hard rules that every argument is a quoted string and no MeTTa variables may appear.
From src/loop.metta:
- Raw LLM string →
$respi. - Parenthesis repair —
helper.balance_parentheses $respi→$resp. Common LLM mistakes (missing closers) are fixed here. - First-character check — if
$respdoes not start with(, the agent receives a reminder prompt instead of a real dispatch; the LLM tries again next turn. - Parse —
catch (sread $response)→$sexpr. On parse failure,HandleErrorrecordsMULTI_COMMAND_FAILURE_.... - Fan out —
(superpose $sexpr)produces one binding per skill call in the tuple. - Evaluate each —
(catch (eval $s)). On success, the result is normalized viahelper.normalize_string. On failure,HandleErrorrecordsSINGLE_COMMAND_FORMAT_ERROR_.... - Aggregate — all results are collapsed into
RESULTS: ((COMMAND_RETURN: (cmd result)) ...). - Feedback — stored as
&lastresults, fed back into the next prompt asLAST_SKILL_USE_RESULTS.
MeTTa evaluates the head of the expression against the AtomSpace. Skills are defined as plain equations:
(= (remember $str) ...)
(= (shell $cmd) ...)
(= (metta $expr) ...)So (shell "ls") matches the equation for shell and runs its body.
Bridges enter via:
(py-call (module.function args))for Python.(translatePredicate (predicate ...))and!(import_prolog_function name)for Prolog.
HandleError appends to the &error state. When addToHistory runs, if &error is non-empty it is concatenated as ERROR_FEEDBACK:. On the next turn the agent sees the error and has the opportunity to correct course.
- reference-internals-loop.md — the full turn structure.
- reference-internals-extension-points.md — where to hook in new skills.
- tutorial-03-writing-a-custom-skill.md — end-to-end skill addition.