Run the Familiar in REPL mode (interactive), single-shot mode, or ACP server mode.
mix cantrip.familiar # REPL mode
mix cantrip.familiar "explain this codebase" # single-shot
mix cantrip.familiar --acp # ACP stdio serverOptions
--acp— start as an ACP stdio server instead of REPL--diagnostics— print the cookie + remsh attach command on stderr (the BEAM is named regardless; this flag just makes the attach affordance visible)--json— output events as JSONL stream (for piping/scripting)--loom-path PATH— store the loom as JSONL at this path. When omitted, the loom is workspace-keyed Mnesia (BEAM-native).--max-turns N— maximum turns per episode (default: 20)--help— show this help
Loom backend
REPL and single-shot promote the BEAM to a workspace-stable named
node and use Mnesia (disc_copies) keyed to the workspace as the
loom backend. The same workspace re-summons the same loom across
restarts, with prior turns visible as loom.turns.
Pass --loom-path PATH to use JSONL instead, when you want a
portable, exportable, human-readable trace.
Summary
Functions
Build the Familiar from launcher opts. Pure construction — no process is started, no LLM call is made.
Workspace-stable node name. Two distinct workspaces produce two
distinct names (so they don't share a Mnesia schema); the same
workspace produces the same name across launches (so Mnesia's
per-node disc_copies find the prior data).
Parses the task arguments into a routing decision.
Functions
Build the Familiar from launcher opts. Pure construction — no process is started, no LLM call is made.
Storage policy:
:loom_pathset → JSONL at that path (caller's explicit portable-trace choice)- otherwise → workspace-keyed Mnesia, via
Cantrip.Familiar.new/1's Mnesia-by-:rootdefault (which the launcher always sets)
No defaulted JSONL — the launcher's job is to enable the BEAM-native posture the substrate documents, not to ship past it.
Raises KeyError if :llm is missing from opts. The launcher
always passes :llm; a missing one is a programmer error, not a
runtime condition.
Workspace-stable node name. Two distinct workspaces produce two
distinct names (so they don't share a Mnesia schema); the same
workspace produces the same name across launches (so Mnesia's
per-node disc_copies find the prior data).
@spec parse_args([String.t()]) :: {:help, %{opts: keyword()}} | {:acp, %{opts: keyword(), diagnostics: boolean()}} | {:repl, %{opts: keyword(), intent: nil | String.t(), diagnostics: boolean()}}
Parses the task arguments into a routing decision.
Pure function returning one of:
{:help, %{opts: opts}}— print usage and exit{:acp, %{opts: opts, diagnostics: bool}}— run as ACP stdio server{:repl, %{opts: opts, intent: nil | binary, diagnostics: bool}}— run interactive REPL (when intent is nil) or single-shot
diagnostics is mode-agnostic: any mode (REPL, single-shot, ACP) may
request the remsh-attach affordance via --diagnostics. ACP, REPL, and CLI
are projections of the same runtime; the diagnostic node is part of that
runtime, not an ACP-specific concern.