MINARA

Subcommands

Every pre-REPL `minara <subcommand>` invocation

Pre-REPL subcommands are dispatched from apps/agent/src/gateway/cli.ts and each delegates to a focused module under apps/agent/src/gateway/*-cli.ts. Every subcommand in this page runs once, prints its result, and exits.

minara / minara chat

Start the interactive REPL. Bare minara and minara chat are equivalent entry points. The process drops into readline after running the first-run wizard (if needed), connecting to configured MCP servers, and printing the cheat sheet.

minara
minara chat

See Slash Commands for what's available inside the REPL.

minara setup / minara init

Run the interactive first-run wizard. Configures the LLM provider (Anthropic / OpenAI / OpenRouter / Minara gateway), logs into Minara, probes your existing ~/.minara/ data dir for importable state, scaffolds the workspace, runs doctor, and prints a cheat sheet.

minara setup
minara init       # alias

Implementation: apps/agent/src/gateway/setup-wizard.ts.

minara auth status

Print every configured auth profile plus a summary of which *_API_KEY env vars are set.

minara auth status

Currently status is the only auth action. More actions will be added under the same namespace rather than at the top level.

minara login <provider>

Authenticate with a provider and persist the credential to the encrypted profile store under $dataDir/.

minara login minara
minara login anthropic
minara login anthropic --api-key sk-ant-...
minara login anthropic-api-key --api-key sk-ant-...
minara login openai
minara login openai --api-key sk-...
minara login openrouter --api-key sk-...
minara login xai
minara login xai --api-key xai-...
minara login ollama --api-key <key>
minara login ollama --api-key <key> --base-url http://localhost:11434
minara login minara --base-url https://api.minara.example

Providers: minara, openai, openai-api-key, anthropic, anthropic-api-key, openrouter, xai, ollama.

minara login minara (no --api-key) uses Minara's device sign-in flow. It prints a short code and a verification URL — open the URL in any browser (your own machine or a phone), approve the request, and the CLI detects the new session automatically. No loopback port to forward, works headless / over SSH. The session is a refresh-rotating OAuth session (same as the web UI sign-in); on servers that predate the device grant the CLI falls back to a Google-passthrough sign-in that saves a single long-lived token. Pass --api-key <KEY> instead to save a long-lived API key.

openai-api-key is a shorthand for openai --api-key …. The xAI OAuth flow opens auth.x.ai in your browser and listens on 127.0.0.1:56121/callback; in SSH sessions, forward the port first: ssh -L 56121:127.0.0.1:56121 <host>.

minara login ollama saves an Ollama Cloud key (from ollama.com/settings/keys). Pass --base-url to point at a self-hosted or local Ollama (for example http://localhost:11434) instead of the cloud default https://ollama.com.

minara login openai uses OpenAI's device-code flow (the same one the official codex CLI ships). It prints a short user code and a URL — open the URL in any browser (your own machine, a phone, a laptop), enter the code, and the CLI detects the new session automatically. No loopback port to forward, works headless / over SSH out of the box. As a fast path, if ~/.codex/auth.json exists and has fresh tokens (you've already run the codex CLI), Minara imports them and skips the device-code round trip.

The prior PKCE-loopback flow was retired in 2026-05 — OpenAI's public Codex client_id rejects arbitrary loopback redirect_uris with AuthApiFailure: unknown_error, so the redirect-based flow never worked for third-party integrations.

OpenAI OAuth and OpenAI API-key profiles live in separate auth-store slots and coexist; auto-select prefers OAuth when both are configured. OPENAI_API_KEY env alone does NOT auto-select OpenAI for the LLM (commonly used only by TTS / embeddings tools); run minara login openai --api-key $OPENAI_API_KEY to opt the LLM path in.

Anthropic mirrors the same shape: anthropic does the Claude.ai PKCE OAuth flow, anthropic-api-key writes a direct API key from console.anthropic.com into the dedicated anthropicApiKey profile slot. Both can coexist — auto-select prefers OAuth, and you can switch between them at any time via Settings → Provider in the web UI. The API-key slot survives gateway restart without depending on $dataDir/env being sourced (the env-file path was the pre-1b936e08 behavior and has been retired).

Flags:

  • --api-key <key>: pass the key non-interactively. Otherwise the wizard prompts for it.
  • --base-url <url>: override the provider's default base URL (only meaningful for openrouter and minara).

Implementation: apps/agent/src/gateway/auth-cli.ts.

minara logout <provider>

Clear a stored profile. The provider list matches login.

minara logout minara
minara logout openai
minara logout openai-api-key
minara logout anthropic
minara logout anthropic-api-key
minara logout xai

minara skills <action>

Manage vendored external SKILL.md packages under apps/agent/src/skills/external/. See The Skill System for how external skills are surfaced to the agent.

minara skills list
minara skills search <query> [--owner <owner>] [--limit <n>]
minara skills install <owner/repo>[@<skill>] [--id <prefix>] [--force]
minara skills add <git-url> [--ref <ref>] [--id <id>] [--subpath <dir>] [--note <text>] [--force]
minara skills upgrade <id> [--ref <ref>]
minara skills remove <id>

Actions:

  • list: print every installed external skill with its upstream URL, ref, commit, license, and updated-at timestamp.
  • search <query>: search the skills.sh ecosystem, ranked by install count. Prints owner/repo@skill ids to pass to install. Optional --owner restricts to one GitHub owner.
  • install <owner/repo>[@<skill>]: install a skill from the skills.sh ecosystem. Downloads via the bundled skills CLI, then writes a tracked Minara package under the runtime skills dir. A bare owner/repo installs every skill in the repo; @skill installs one. Warns when an installed skill has no LICENSE.
  • add <git-url>: clone the repository, detect the license, and register the skill. Refuses to proceed if the upstream has no LICENSE and --force is not passed.
  • upgrade <id>: re-fetch an existing skill. Optional --ref pins to a tag or commit.
  • remove <id>: delete the vendored directory and its .minara-skill.json manifest.

Implementation: apps/agent/src/gateway/skills-cli.ts.

minara scenarios <action>

Manage learned scenarios from the self-learning scenario system (Phase 2). Requires SCENARIO_LEARNING=1 in .env.

minara scenarios pending                         # show graduation queue
minara scenarios list [--state=<state>] [--sort-by-usage]
minara scenarios show <id>                       # full detail (JSON)
minara scenarios approve <id>                    # graduate → active in classifier
minara scenarios reject <id> --reason=<reason>   # reject with reason
minara scenarios deprecate <id>                  # remove graduated scenario
minara scenarios purge                           # clean up old entries

Actions:

  • pending (default) — list scenarios that passed the Wilson confidence gate and are awaiting operator approval.
  • list — all learned scenarios. --state=graduated filters; --sort-by-usage orders by times_used descending.
  • show <id> — dumps the full LearnedScenario as JSON (metaPlan, analyze, keywords, confidence, source turns).
  • approve <id> — transitions quarantined → graduated and hot-reloads the scenario into the classifier immediately.
  • reject <id> --reason=... — transitions to rejected. Default reason: operator_rejected.
  • deprecate <id> — transitions a graduated scenario to rejected and removes it from the in-memory classifier.
  • purge — deletes rejected / stale proposed entries older than 90 days + old miss candidates older than 30 days.

Source: apps/agent/src/gateway/scenarios-cli.ts.

minara agents <action>

Manage Custom Agents — saved bundles of system prompt + skill subset + tool subset + risk ceiling + triggers. See Custom Agents for the full guide.

minara agents list [--archived]
minara agents get <id>
minara agents create --from <file.json>
minara agents update <id> --from <patch.json>
minara agents archive <id>
minara agents run <id> [--input "<text>"] [--test]
minara agents export <id>
minara agents import [--from <file.json>]

Actions:

  • list (default) — print every registered agent with its version, risk ceiling, discovery mode, and attached triggers. --archived includes soft-deleted rows.
  • get <id> — dump the full AgentDefinition as JSON, including snapshot bookkeeping.
  • create --from <file.json> — insert from a JSON file conforming to AgentDefinitionSchema. Interactive create lives in the REPL (/agents create).
  • update <id> --from <patch.json> — apply a partial AgentUpdatePatch. Bumps version on any meaningful change. Rejected if the agent's source is file:... — file-sourced rows are PATCH-locked; edit the file on disk instead.
  • archive <id> — soft-delete. Tears down attached cron and event triggers. In-flight workflow instances that reference the agent continue against their stored snapshot.
  • run <id> [--input "..."] [--test] — start an ad-hoc run. Streams workflow:* events to stdout until the run terminates, then prints the final __adhoc__ output payload. --test tags the instance test_run=1, which forces the fund-confirm gate even when MINARA_SKIP_FUND_CONFIRM=1 is set.
  • export <id> — print the agent's JSON to stdout. Pipe to a file for sharing.
  • import [--from <file.json>] — insert from JSON via file or stdin. Inverse of export.

Source: src/gateway/agents-cli.ts.

minara script-risk <action>

Inspect the script risk gate audit log. Every gateScriptRisk() decision (reject / confirm / allow) writes one row to the script_risk_decisions SQLite table; this command surfaces it.

minara script-risk list [--verdict=<reject|confirm|allow>]
                        [--session=<id>] [--workflow=<id>]
                        [--tool=<name>] [--since=<iso>]
                        [--limit=<N>] [--json]
minara script-risk show <id>

Filters:

  • --verdict — only show rows whose verdict matches.
  • --session / --workflow / --tool — narrow to a specific session / workflow definition / tool name.
  • --since — ISO-8601 timestamp; only show decisions newer than this.
  • --limit — cap result count (1..1000, default 50 for list, 100 for the HTTP endpoint).
  • --json — emit raw JSON instead of the human-readable table.

show <id> dumps a single decision row with the full findings array and the truncated evidence preview (the script body itself is NEVER stored — only its sha256).

Source: apps/agent/src/gateway/script-risk-cli.ts.

minara btc-cycle refresh

Maintainer-only refresh of the BTC halving cycle data committed under apps/agent/src/skills/builtin/btc-cycle/data.ts. Pulls new daily OHLC tuples from Binance (BTCUSDT 1d klines) primary, falls back to Bitstamp on failure, and rewrites data.ts in-place.

minara btc-cycle refresh                                  # binance primary, bitstamp fallback
minara btc-cycle refresh --dry-run                        # preview, don't write
minara btc-cycle refresh --from 2025-10-01                # override start date
minara btc-cycle refresh --promote-ath                    # if a new ATH is detected, fold into CYCLES[last]
minara btc-cycle refresh --promote-bottom 2026-10-24 36800
                                                          # append a new cycle entry whose
                                                          # botDate / botPx is the just-confirmed bottom

Behavior:

  • Default window: from BTC_DAILY_OHLC[last].ts + 1d to today.
  • Detects a new ATH (any candle whose high exceeds the current CYCLES[last].topPx) and prints a warning unless --promote-ath is passed.
  • Detects the post-top low across embedded + fetched candles and prints it as informational. Bottom promotion is human-judgement (R7 confirmation requires 3+ months sideways) — --promote-bottom is the operator flag.
  • Writes DATA_REFRESHED_AT to the current ISO timestamp.

Available also as npm run btc-cycle:refresh -- <flags> for direct invocation outside the gateway.

Source: apps/agent/src/cli/btc-cycle-refresh.ts.

minara institution <action>

Operator-facing batch surface for Institution Mode self-learning (persistence, Phase B reflections, finalize). Mirrors the REPL /institution-* commands but runs non-interactively — the cron entry point + audit / batch finalize live here.

minara institution history [--ticker BTC] [--limit 20] [--json]
minara institution finalize <run_id> [--reason "closed at +12%"]
minara institution reflect-pending [--max N] [--json]
minara institution reflect <run_id> --window 1d|7d|30d|90d|180d|365d|lazy [--json]
minara institution help

Actions:

  • history (default) — list recent runs from institution_runs with PM rating + holding status + per-window alpha summary. --json emits the same data plus all reflection rows for downstream tooling.
  • finalize <run_id> — flip a run's holding_status to finalized so the daily reflect cron stops accumulating reflections on it. Idempotent on already-finalized runs. --reason is stored for audit.
  • reflect-pending — the daily cron entry point. Walks every open / auto_stale run, evaluates the next-due standard window (1d / 7d / 30d / 90d / 180d / 365d), pulls Yahoo prices, computes raw_return + alpha_return vs the asset-class benchmark, asks the quick LLM for a 2–4 sentence reflection, and persists. Auto-stale promotion (open → auto_stale) happens here when a run exceeds INSTITUTION_AUTO_STALE_DAYS (default 90). Pair with cron / systemd-timer for daily 03:00 UTC.
  • reflect <run_id> --window ... — manually trigger a single reflection for one run. --window lazy is equivalent to the Phase 0 retrospective refresh path (current-time snapshot, no (run_id, window) UNIQUE collision); the standard windows (1d ... 365d) anchor the exit price to started_at + window.

Exit codes: 0 success, 1 runtime error, 2 usage error.

Source: apps/agent/src/gateway/institution-cli.ts.

minara profile <action>

Manage personalization (financial profile + tags + custom prompt) from the shell. Mirror of the REPL /profile slash command but positional, with no pickers — best for scripts and CI. Tag names accept either canonical form ("Risk Profile") or slug form (risk-profile).

minara profile show                              # snapshot
minara profile set risk-profile Conservative     # set a tag
minara profile clear risk-profile                # clear a tag (sets value=null, source=user)
minara profile prompt show                       # print custom prompt
minara profile prompt set "Reply concisely."     # set custom prompt
minara profile prompt clear                      # clear custom prompt
minara profile help                              # full usage + tag table

All writes are recorded with source: "user", which beats both learned_preference (preference-system bridge writes) and inferred (autoscan rebuild) under the three-tier precedence rule.

Source: apps/agent/src/gateway/profile-cli.ts.

minara preferences <action>

Manage learned preferences mined by the preference-evolution system (Financial Auto-Memory). M1 shipped read-only commands; M2 adds approve / reject / deprecate for operator overrides. The prefs alias is also accepted. Approving a preference here works even when PREFERENCE_LEARNING=0 — manual overrides are always available.

minara preferences pending                       # awaiting approval
minara preferences list                          # all preferences
minara preferences list --state active           # filter by state
minara preferences list --kind hard_constraint   # filter by kind
minara preferences list --dimension asset_class  # filter by dimension
minara preferences show <id>                     # full detail (JSON)
minara preferences approve <id> [--reason "..."]    # proposed → active
minara preferences reject <id> [--reason "..."]     # proposed → rejected (terminal)
minara preferences deprecate <id> [--reason "..."]  # active → deprecated
minara preferences undo <id>                         # M3: strong-signal auto-activations, within the undo window

Transitions are CAS-guarded — concurrent writers (REPL + CLI + REST across the same DB) can't double-apply or silently overwrite each other. A failed CAS surfaces as a non-zero exit + clear error message ("invalid transition from X (or another writer beat us to it)").

undo is the M3 exit path for rows that the keyword scanner auto-activated via a strong signal (never, 绝不, kill switch, …). Eligibility: auto_activated_at IS NOT NULL AND within PREFERENCE_HARD_UNDO_WINDOW_HOURS (default 24h). Manual approvals and stale auto-activations must use deprecate instead — the CLI surfaces a targeted error message pointing at the right path.

Source: apps/agent/src/gateway/preferences-cli.ts.

minara learning <action>

Observability + offline tuning infrastructure for the self-optimization loop (decision capture → multi-horizon backtest → reward → methodology instance BO).

minara learning stats [--json]
minara learning tune-methodology --dry-run [--json]
minara learning tune-methodology profiles show [--json]
minara learning audit run [--window-days N] [--json]
minara learning audit show [--latest | --pass <id>] [--json]
minara learning audit trend [--days N] [--json]
minara learning audit findings [--severity high|medium|low] [--latest | --pass <id>] [--json]
minara learning replay --config <path.json>   # LEARNING_CONFIG BO, placeholder
minara learning help

stats [--json]

Readonly data-readiness report covering trade_history, methodologies, decision_history, decision_outcomes, and reward distribution. Always safe to run — ignores LEARNING_TUNING_ENABLED.

Key fields:

  • READY_FOR_BO=true|false — the gate for running BO cycles (≥100 evaluated trades + ≥20 unique methodology hits).
  • decision_history — BUY/SELL/HOLD counts + capture source distribution + quoted-price coverage (hallucination defense stats).
  • outcome_coverage — per-horizon counts (1d/3d/1w/1m).
  • rewards — mean / std / p50 per decision type + top-5 asset classes by decision volume.

tune-methodology --dry-run [--json]

Lists the (template, asset_class) buckets that would be processed by the next BO cycle, sorted by tunability_score. Prints each bucket's gate pass/fail and the skipped-bucket breakdown by first-failed gate. Does NOT invoke the Python BO harness — this is plan-only.

Full execution (beyond --dry-run) is intentionally unwired: it requires METHODOLOGY_INSTANCE_TUNING_ENABLED=true and the Python harness under tools/tuning/ to be activated by an operator.

tune-methodology profiles show [--json]

Prints the effective BUILTIN_PROFILES merged with any JSON override file (default path: $MINARA_DATA_DIR/methodology-tuning-profiles.json). Use for debugging why a specific asset class is/isn't getting tuned.

replay --config <path>

Placeholder for the LEARNING_CONFIG BO replay harness (a separate track from methodology instance tuning). Gated by LEARNING_TUNING_ENABLED=true; short-circuits to { skipped: "tuning_disabled" } otherwise.

audit run [--window-days N] [--json]

Runs one inline pass of the methodology audit subsystem and persists the report to methodology_audit_reports. Six dimensions: synthesis decision stability, graduation false-positive rate, attribution integrity, asset-class coverage, quarantine churn, and cron health. Composite 0-100 with bands healthy / watch / degraded / alarm. Never mutates learning state — the e2e test asserts byte-level immutability of the four learning tables before and after every pass. Honours DISABLE_METHODOLOGY_AUDIT=1 (returns band=disabled placeholder, does not persist).

audit show [--latest | --pass <id>] [--json]

Prints a single audit report. --latest (default) returns the most recent row; --pass <id> looks up a specific pass id.

audit trend [--days N] [--json]

Composite score history over the last N days (default 30). Plain text shows an ASCII sparkline followed by per-row timestamps, composite, band, and pass id prefix.

audit findings [--severity high|medium|low] [--latest | --pass <id>] [--json]

Drills into the findings list of a single report. Each finding carries a severity, the dimension that produced it, a message, and structured metrics. Advisory actions (e.g. requantize, investigate_attribution) are listed alongside with the CLI command the operator would run.

Source: apps/agent/src/gateway/learning-cli.ts.

minara research <topic> [--mode light|heavy]

Run the deep-research pipeline directly, bypassing the REPL. Prints the generated summary and exits. Useful for scripted research runs and cron jobs.

minara research "BTC ETF flows this quarter"
minara research "macro risks for Solana" --mode heavy

Modes:

  • light (default): single-pass research with a small tool budget.
  • heavy: multi-phase research with a methodology and verify step. Slower, more thorough, more expensive.

Implementation lives in apps/agent/src/deep-research/ and is invoked via app.deepResearchPipeline.run(...).

minara doctor [--probe-llm] [--anonymous]

Run a full health check and print a colorized report. Checks LLM auth, Minara auth, MCP servers, tool registration, workspace files, env vars, data directory, SQLite state, and memory health (a section covering methodology graduation/quarantine counts, role_memory pending-72h backlog, embedding-state distribution, edge totals + top entities, and snapshot dirty counters). Exits non-zero if any check fails.

minara doctor
minara doctor --probe-llm     # also send a tiny ping to verify LLM connectivity
minara doctor --anonymous     # bucket every count to <10 / 10-99 / 100-999 / ...

Flags:

  • --probe-llm — calls the configured model with a one-token prompt. Without it, the LLM check only validates credentials and selection.
  • --anonymous — replaces every numeric count in the memory health section with a bucket label so the output can be safely shared in an issue or screenshot without leaking deployment scale. Buckets: <10, 10-99, 100-999, 1000-9999, 10000+.

Honours MINARA_DATA_DIR so operators running against a non-default data directory diagnose the right database.

Implementation: apps/agent/src/gateway/doctor-cli.ts.

minara doctor --fix [--apply] [--only <actions>]

Idempotent automated maintenance over the memory + learning stores. Every action satisfies three contracts: idempotent (replay-safe), reversible or non-destructive (UNIQUE constraints catch replays; demotion only ever raises quarantine), and no LLM calls by default. Without --apply, the command runs as a dry-run that lists what would happen and writes nothing — including no audit rows.

minara doctor --fix                                 # dry-run report
minara doctor --fix --apply                         # run the default action set
minara doctor --fix --apply --only edges,embeddings # restrict to a subset
minara doctor --fix --apply --only reflect_pending  # opt into the LLM-backed action

Default action set (runs when --only is omitted):

  • embeddings — backfill rows with embedding_state IN ('pending','failed') via MemoryStore.backfillEmbeddings(). Skips cleanly when EMBEDDING_PROVIDER=disabled.
  • edges — replay the deterministic memory_edges extractor over every memory + role_memory row. UNIQUE constraint makes the second run insert zero new edges.
  • methodology_demotion — quarantine methodologies whose Wilson lower bound has fallen below LEARNING_CONFIG.demotionWilsonThreshold (default 0.40) AND have at least LEARNING_CONFIG.minUsesBeforeDemotion uses (default 20). Always raises quarantine from 0 to 1; never lowers it, never touches confidence.

Opt-in action (NOT in the default set; LLM-backed):

  • reflect_pending — invoke the role-reflector for every role with pending rows past the policy's age threshold. This calls llm.createMessage() for Stage 1 classification + Stage 2 lessons. Excluded from the default set so --apply never spends tokens unintentionally.

Hard safety envelope (covered by negative tests):

  • never graduates a methodology (Wilson upward stays manual)
  • never activates a learned_preferences row (hard_constraint especially never auto-activates)
  • never DELETEs any row (orphans surface in the dry-run report only)
  • never rewrites role_memory.reflection (LLM authorship attribution must stay intact)
  • never modifies audit_log (append-only)

Every applied action writes an audit_log row tagged tool_call='doctor.fix.<name>' with structured detail; dry-run leaves the table untouched. Honours MINARA_DATA_DIR.

Implementation: apps/agent/src/gateway/doctor-fix.ts.

minara memory export [<out-dir>] [--include-constraints] [--sign]

Snapshot the agent's learned memory to a markdown tree humans can git diff, grep, hand-edit, and (with --sign) round-trip back via memory import. Output layout under <out-dir>:

<out-dir>/
  index.md                                # toc + schema_version + instance_id
  methodologies/<asset_class>/<id>.md     # per-methodology, with frontmatter
  preferences/<dimension>/<id>.md         # per-preference (active state only)
  preferences/README.md                   # constraint-exclusion banner
  trade-cases/<id>.md                     # one file per reflected role_memory
  assets/<TICKER>.md                      # compiled-page snapshots
  signature.txt                           # optional: line-per-file HMAC

Default <out-dir> is <dataDir>/exports/<timestamp>/. The path is outside the LLM sandbox (<dataDir>/sandbox/files), so a prompt-injected memory cannot leak the export back through a read_file tool call. Passing an explicit <out-dir> that resolves into the sandbox is rejected with refusing to export into the LLM sandbox.

Flags:

  • --include-constraints — without this flag, hard_constraint preferences are excluded from BOTH the per-preference files AND the asset compiled-page surface (they encode user-specific risk caps; one-way leakage hazard). The flag opts in.
  • --sign — compute a per-file HMAC-SHA256 against this instance's local key (instance_meta.hmac_key) and write a manifest at signature.txt. The manifest enables memory import channel A (preserves confidence + state). The HMAC key itself never leaves the SQLite DB; only the SHA-256 fingerprint (instance_id, first 16 hex chars) appears in frontmatter.

Honours MINARA_DATA_DIR.

Implementation: apps/agent/src/gateway/memory-export-cli.ts.

minara memory import <in-dir> [--apply] [--approve-hard-constraints] [--allow-path <abs>]

Round-trip the markdown tree produced by memory export back into the agent's stores. Two channels distinguish trusted same-instance restores from unsigned third-party bundles.

minara memory import <in-dir>                            # dry-run
minara memory import <in-dir> --apply                    # commit writes
minara memory import bundle1 --allow-path /tmp/imports   # outside-root override

Channel selection (per-file):

  • Channel A — signed. signature.txt is present AND the file's HMAC verifies against instance_meta.hmac_key AND the bundle's instance_id matches this instance. Methodology imports preserve confidence / quarantine / times_used (via writeMethodology's INSERT OR REPLACE — same-id replays are idempotent). Preferences keep state='active' when present. hard_constraint preferences NEVER auto-activate, even on channel A — the user must approve via /preferences.
  • Channel B — unsigned (default fall-through). Methodologies go through MethodologyStore.create() and land at quarantine=1, confidence=initialConfidence; dedup-match returns the existing row's stats. Preferences land in state='proposed' via PreferenceStore.create(); dedup_key collisions skip silently. role_memory rows arrive as fresh pending entries; reflections are NEVER re-imported.

A bundle marked signed but with one tampered file degrades that file to channel B without invalidating the rest of the bundle.

Flags:

  • --apply — required for any write. Without it, the command runs as a dry-run that prints the per-file disposition and leaves audit_log untouched.
  • --approve-hard-constraints — opt into importing hard_constraint preferences. Even with this flag set, imports are rejected when MINARA_NON_INTERACTIVE=1 is set or the process has no TTY (defense in depth — a hard constraint should only land via a human-driven session).
  • --allow-path <abs> — permit imports from outside <dataDir>/exports/. Relative <in-dir> resolves under --allow-path when set, otherwise under the exports root.

Per-file safety (both channels): a prompt-injection scan checks every body before dispatch (rejects ignore previous instructions, imperative fund verbs, rating-coercion patterns); schema_version must match MEMORY_EXPORT_SCHEMA_VERSION; asset_class must be in the live enum; dimension + kind must be in the typed preference enums. Every applied action — applied or rejected — writes an audit_log row tagged memory_import.signed or memory_import.unsigned (only on --apply).

Honours MINARA_DATA_DIR.

Implementation: apps/agent/src/gateway/memory-import-cli.ts.

minara model <action>

Inspect or persist the active LLM model. Writes to ~/.minara/env when you use a model so the next boot picks it up.

minara model                       # list (default)
minara model list
minara model show                  # show the currently persisted model
minara model use claude-sonnet-4-6

Actions:

  • list (default): print every model the registry knows about with its provider, context window, and cost.
  • show: print the currently persisted AGENT_MODEL value.
  • use <model>: persist AGENT_MODEL=<model> to ~/.minara/env.

Implementation: apps/agent/src/gateway/model-cli.ts.

minara tools <action>

Enumerate the tool registry or dump a tool's full JSON Schema. Boots the full app so the output reflects exactly what the agent sees, including env-gated tools that only appear when their provider is configured.

minara tools                # list (default), grouped by tool set
minara tools list
minara tools show get_price

Actions:

  • list (default): every registered tool, grouped by tool set, with its permission tier and description.
  • show <name>: full JSON Schema for parameters plus description.

Implementation: apps/agent/src/gateway/tools-cli.ts.

minara config <action>

Dot-path CRUD over safety.json and financial-profile.json under $dataDir/. Lets you edit configuration without hand-editing JSON files.

minara config                              # list (default)
minara config list
minara config path                         # print config file paths
minara config get safety.daily_spend_cap
minara config set safety.daily_spend_cap 500

Actions:

  • list (default): print all current values from both config files.
  • path: print the absolute paths of the config files.
  • get <key>: read a dot-path key.
  • set <key> <value>: write a dot-path key. Values are parsed as JSON if possible, otherwise treated as strings.

Implementation: apps/agent/src/gateway/config-cli.ts.

minara gateway <action>

Configure outbound messaging terminals (Telegram, Discord, Slack, Lark, WeCom, DingTalk, WeChat OA, QQ, LINE, Mattermost, Teams, Google Chat, BlueBubbles, Matrix, WhatsApp, Signal, Email, Home Assistant — 18 platforms total) used by the agent to send alerts and notifications.

minara gateway                   # list (default)
minara gateway list
minara gateway add               # interactive picker, no positional id
minara gateway add telegram      # jump straight to one provider
minara gateway test telegram
minara gateway remove telegram

Actions:

  • list (default): enumerate every configured messaging provider and its status.
  • add (no provider id): drop into an interactive picker that lists every implemented platform (numbered 1 through 18), shows which are already configured () vs not (), and accepts a number, a provider id (case-insensitive), or q / blank to quit. Three invalid attempts auto-cancel with exit code 0. After saving one provider, a next-action menu offers t (ping test), a (configure another), or q (quit). This is the recommended starting point for new operators.
  • add <provider>: interactively collect required fields for a specific provider and write them into ~/.minara/env. Masked input for secrets; blank lines skip a field.
  • test <provider>: send a test message via the configured provider. Instantiates the gateway via spec.factory({dataDir}) and calls .send({text: "✅ Minara gateway test ping"}).
  • remove <provider>: strip the provider's env lines.

Implementation: apps/agent/src/gateway/gateway-cli.ts. The picker logic exports two pure parsers (resolvePickerInput, resolveNextActionInput) and a top-level helper isProviderConfigured(spec, values) shared with runList, all covered by 21 unit tests in tests/unit/gateway/gateway-add-interactive.test.ts.

minara serve

Start the HTTP API gateway — the same surface that npm run serve and node dist/gateway/server.js expose, but reachable through the minara CLI so operators who installed via the quick installer never have to cd into the clone directory.

minara serve                              # foreground, Ctrl+C to stop
minara serve --ui                         # gateway + Web UI (preview) in one shell
minara serve --ui-dev                     # gateway + Vite dev server (hot reload)
minara serve -p 9090 --auth-token $TOK    # override port + bearer
minara serve --daemon                     # detach, write PID + log files
minara serve --status                     # is the daemon running?
minara serve --stop                       # graceful SIGTERM, up to 10s

Flags:

  • -p, --port <N> — listen port. Also reads GATEWAY_PORT; default 8080.
  • --auth-token <T> — bearer token required on /v1/*. Also reads GATEWAY_AUTH_TOKEN. Empty disables auth (dev only).
  • --ui — co-launch the Web UI in preview mode on port 4173. If apps/web-ui/dist/ is missing or older than apps/web-ui/apps/agent/src/, Minara auto-builds it before spawning preview. A file lock under apps/web-ui/dist/.build.lock prevents concurrent rebuilds.
  • --ui-dev — co-launch the Web UI in Vite dev mode on port 5173 (hot reload). Mutually exclusive with --ui.
  • --ui-port <N> — override the UI port (preview defaults to 4173, dev to 5173).
  • --no-build — skip the auto-build check. Assumes apps/web-ui/dist/ is fresh; exits non-zero with a clear error if it is missing.
  • --ui-pid-file <path> / --ui-log-file <path> — override the per-UI pidfile / logfile paths (daemon mode only). Defaults to $MINARA_DATA_DIR/web-ui.pid and $MINARA_DATA_DIR/logs/web-ui.log.
  • -d, --daemon — spawn a detached child that keeps running after the terminal closes. With --ui or --ui-dev, the daemon tracks both the gateway and the Web UI subprocess.
  • --stop — read the PID file, send SIGTERM, wait up to 10 seconds for graceful shutdown, then remove the PID file. With --ui, also drains the UI subprocess and removes web-ui.pid (with a PID-recycling guard so a stale pidfile pointing at an unrelated process is removed without signaling it).
  • --status — report whether the daemon is running. Exits 0 if alive, 3 if not (LSB init-script convention). Reports both gateway and UI PIDs when both are running.
  • --pid-file <path> — override the gateway PID file path (default: $MINARA_DATA_DIR/server.pid, typically ~/.minara/server.pid).
  • --log-file <path> — override the log file path (default: $MINARA_DATA_DIR/logs/server.log).

The daemon child re-execs the same minara serve command without --daemon and inherits the parent's environment, so .env values loaded before the fork flow through to the background process. Signal handling mirrors the foreground path: SIGTERM / SIGINT drain the ApiGateway + call app.shutdownAsync() so in-flight inbound messaging work finishes before the SQLite handle closes.

For production-grade supervision (restart-on-crash, journal integration, boot-time start), wire minara serve into systemd or your preferred supervisor instead of relying on --daemon.

Co-launching the Web UI

With --ui or --ui-dev, minara serve spawns the Web UI as a child process and orchestrates both lifecycles:

  • Foreground: outputs from both processes are prefixed with [gateway] / [ui] so the terminal multiplexes cleanly.
  • Daemon (--daemon): writes a second pidfile ($MINARA_DATA_DIR/web-ui.pid) for the UI subprocess. Both stdout and stderr go to separate log files (server.log and web-ui.log).
  • --stop drains the UI subprocess first (so its readiness probe does not race a half-shut gateway), then SIGTERMs the gateway daemon, then cleans up both pidfiles.
  • PID-recycling guard: if the UI pidfile points at a PID that the OS has reused for an unrelated process (a shell, editor, etc.), --stop removes the pidfile but does NOT signal the recycled process. The check uses ps argv matching against node / npm / vite / tsx plus vite / web-ui in the argv list.
  • Auto-build inspection: before spawning Vite preview, inspectWebUiDist(repoRoot) compares the mtime of apps/web-ui/dist/index.html against apps/web-ui/apps/agent/src/, package.json, vite.config.ts, and apps/web-ui/index.html. Any source file newer than the dist triggers a rebuild. --no-build skips this check and is the right flag for CI / production deploys where the build pipeline already produced a fresh dist/.

Implementation: apps/agent/src/gateway/serve-cli.ts. minara serve and npm run serve share the same startServerForeground() helper so both paths boot through one code path. The arg parser is exported as parseServeArgs and pinned by 14 unit tests in tests/unit/gateway/serve-cli-args.test.ts. End-to-end smoke (cold build, foreground / daemon, PID-recycle guard, --no-build error) lives in scripts/smoke-serve-ui.sh.

minara update

Self-update to the latest published version of the agent. Detects the install source (global npm, vendored, Docker) and invokes the right upgrade path.

minara update

Implementation: apps/agent/src/core/update-check.ts.

minara migrate

Two modes:

  1. Schema migration / hermes import (legacy, no positional sub): Initialize or migrate the SQLite schema; optionally import from a hermes / openclaw dataset. Safe to run repeatedly; migrations are idempotent.

    minara migrate                                # schema only
    minara migrate --from hermes                  # import from ~/.hermes
    minara migrate --from openclaw --openclaw ~/oc  # custom path
    minara migrate --dry-run --verbose            # report only
  2. M5 bundle export / import / manifest (export / import / manifest positional sub-command):

    minara migrate export [--packages defaults|all|csv]
                           [--output PATH]
                           [--passphrase-env ENV]
    
    minara migrate import <bundle.tar.gz>
                           [--strategy merge|replace|audit-only]
                           [--packages defaults|all|csv]
                           [--confirm-hard]
                           [--passphrase-env ENV]
    
    minara migrate manifest <bundle.tar.gz>

    The bundle is a .tar.gz containing per-package JSON files plus manifest.json and (optionally) secrets.json.enc. The 10 packages and their default-on flag:

    PackageDefaultNotes
    profilefinancial_profile row + 11-dim user_tags (preserves user/learned/inferred source).
    preferenceslearned_preferences (active + deprecated). hard_constraint rows require --confirm-hard on import.
    methodologiesAll graduated methodologies, full asset-class coverage.
    memoriesmemories rows in personalization / preference / strategy / trade_note / observation categories.
    scenarioslearned_scenarios (graduated). LLM behavior may differ across instances.
    workspaceUSER.md, SOUL.md, MEMORY.md, AGENTS.md from ~/.minara/workspace/.
    trade_historyFull trade_history table. Often large; reconstructible from chains.
    external_skillsSkill clone-URL list. Import writes a pending-skill-imports.json for manual skills add follow-up.
    settingsAllowlisted env vars only (no *_KEY / *_SECRET / *_TOKEN). Import writes a pending-env.sh to source.
    secrets⚠️ API keys + OAuth + wallet keys. Forced AES-256-GCM + PBKDF2 encryption; import requires --strategy=replace.

    --packages accepts defaults, all, comma-separated ids, or -id to remove (e.g. defaults,trade_history,-scenarios).

# Quick export of the default 6 packages
minara migrate export --output ./bundle.tar.gz

# Inspect a bundle without importing
minara migrate manifest ./bundle.tar.gz

# Dry-run import — no writes
minara migrate import ./bundle.tar.gz --strategy audit-only

# Real import with hard-constraint preferences allowed through
minara migrate import ./bundle.tar.gz --strategy merge --confirm-hard

Implementation: apps/agent/src/gateway/migrate-cli.ts + apps/agent/src/gateway/migrate-bundle-cli.ts + apps/agent/src/learning/migration/.

minara strategy-rl <action>

Operator entry point for the opt-in Strategy Skill RL pilot. Requires MINARA_STRATEGY_SKILL_RL_ENABLED=1. Promotion evaluation defaults to dry-run; candidates are promoted or rejected only when the operator passes explicit apply flags.

Usage:
  minara strategy-rl evaluate <candidate-version-id> [--baseline <version-id|builtin>] [--apply] [--reject-on-failure] [--min-episodes <n>] [--min-baseline-episodes <n>] [--min-mean-delta <n>] [--max-invalid-rate <n>] [--limit <n>] [--session <id>] [--user <id>] [--json]
  minara strategy-rl promote  <candidate-version-id> [same options as evaluate]
  minara strategy-rl evaluations [--candidate <version-id>] [--limit <n>] [--json]
  minara strategy-rl evaluation <evaluation-id> [--json]
  minara strategy-rl external-context health [--json]
  minara strategy-rl external-context collect --goal <text> --symbol <symbol> --interval <tf> [--as-of <iso>] [--source kb_search|fmp_news|web_search] [--lookback-days <n>] [--max-items <n>] [--freeze] [--json]
  minara strategy-rl external-context audit-suite [--suite <id>] [--all] [--json]
  minara strategy-rl benchmark seed-defaults [--json]
  minara strategy-rl benchmark seed-external-context-defaults [--json]
  minara strategy-rl benchmark cases [--suite <id>] [--all] [--json]
  minara strategy-rl benchmark add-case --goal <text> --symbol <symbol> --interval <tf> [--suite <id>] [--name <text>] [--tag <tag>] [--external-context-json <json>|--collect-external-context] [--external-context-as-of <iso>] [--external-context-source kb_search|fmp_news|web_search] [--json]
  minara strategy-rl benchmark run <candidate-version-id> [--suite <id>] [--case <id>] [--baseline <version-id|builtin>] [--max-iterations <n>] [--external-context-ablation] [--apply] [--reject-on-failure] [--json]
  minara strategy-rl benchmark runs [--candidate <version-id>] [--suite <id>] [--limit <n>] [--json]
  minara strategy-rl benchmark get <run-id> [--json]
  minara strategy-rl benchmark report <run-id> [--json]
  minara strategy-rl preference add --text <text> [--user <id>] [--session <id>] [--source explicit_user|feedback|inferred] [--weight <n>] [--inactive] [--json]
  minara strategy-rl preference list [--user <id>] [--session <id>] [--all] [--limit <n>] [--json]
  minara strategy-rl preference update <preference-id> [--text <text>] [--weight <n>] [--active|--inactive] [--json]

External context workflow:

  1. external-context health --json checks whether the provider and source tools are registered. This is read-only and does not call the news APIs.
  2. external-context collect ... --as-of <iso> --freeze --json previews a normalized replay snapshot and fingerprint before it is saved into a benchmark case. --as-of is the historical generation time; source providers should not return items known after it.
  3. benchmark seed-external-context-defaults creates the curated strategy-rl-external-context-smoke suite.
  4. external-context audit-suite --suite strategy-rl-external-context-smoke --json validates that every active case has replayable context, stable fingerprints, and no temporal leakage before a benchmark run. The audit uses evalStartTime as the generation cutoff when present, otherwise endTime, and reports warnings such as context_asof_after_cutoff, context_window_end_after_cutoff, item_after_cutoff, and item_missing_timestamp.
  5. benchmark run ... --external-context-ablation runs the normal candidate/baseline comparison plus a no-context candidate ablation for context cases.
  6. benchmark report <run-id> --json emits externalContext, externalContextAudit, contextAblation, per-case contextDelta, and the standardized contextAblation.effect.verdict.

The context ablation path is for attribution and test reporting only. It does not enter promotion evidence and does not change the promotion gate.

Source: apps/agent/src/gateway/strategy-rl-cli.ts.


Exit codes

All subcommands follow a shared convention:

CodeMeaning
0Success
1Command ran but failed (network, auth, validation)
2Usage error (bad arguments, unknown subcommand)

The REPL (minara / minara chat) only exits on /quit, signal, or unrecoverable error.

On this page