MALDA™ Reference Manual

The AI-First Programming Language - Version 1.0.11

32. Personal Assistant and CLI

MALDA provides a built-in personal assistant and a set of CLI commands for configuration, scheduled tasks, and status. These features use a standard config directory ~/.malda and an optional config file so you can run an AI assistant from the command line without writing a script.

32.1 Quick start

  1. Run malda onboard (or malda onboard --download-rerank --download-local-llama) to create ~/.malda, skills/, memory/, and a starter config.json with agents.memory, channels.telegram, and provider placeholders.
  2. Set OPENROUTER_API_KEY or add providers.openrouter.apiKey in ~/.malda/config.json.
  3. Optional: malda memory download-rerank installs the ONNX cross-encoder under ~/.malda/models/cross-encoder for agents.memory.rerankMode: onnx.
  4. Run malda agent for interactive chat, or malda agent -m "Your question" for a one-shot reply.

32.2 Commands

32.2.1 malda agent

Runs the default assistant script in interactive or one-shot mode.

The assistant script is resolved in this order:

  1. Path in the MALDA_AGENT_SCRIPT environment variable (if the file exists).
  2. ~/.malda/assistant.malda.
  3. Examples/Assistant/assistant.malda relative to the current directory or the executable (e.g. when run from the repo).

If no script is found, the CLI prints an error and exits.

32.2.2 malda onboard

Initializes the MALDA config directory and a guided starter config.

Run this once before using the assistant, gateway, or cron. The command prints next-step hints (API keys, Telegram, ONNX rerank, malda doctor).

32.2.3 malda status

Prints the current assistant setup and runtime health. Use malda status --json for machine-readable output (config, channels, skills, gateway, memory, cron jobs).

32.2.4 malda gateway

Long-running process for Telegram and optional in-process cron scheduling.

The gateway runs the same assistant.malda as malda agent -c telegram, but also polls ~/.malda/cron.json every minute and spawns malda agent -m "..." for due jobs (with per-job memory scope). Requires a Telegram bot token in config or TELEGRAM_BOT_TOKEN.

Gateway alerts: set channels.telegram.notifyChatId (or MALDA_GATEWAY_NOTIFY_CHAT_ID) to receive Telegram messages on cron failures, gateway crashes, and restarts after a crash. Events are also appended to ~/.malda/gateway-alerts.log. malda doctor reports gateway state and previous crashes via ~/.malda/gateway-crash.json.

32.2.5 malda cron

Manage scheduled jobs stored in ~/.malda/cron.json. Jobs can run via the gateway scheduler, malda cron install (Windows Task Scheduler), or your system cron.

32.3 Config file (~/.malda/config.json)

Optional. The assistant and some built-ins read config from the current directory first (./.malda/config.json), then from the user directory (~/.malda/config.json).

Minimal structure (OpenRouter only):

{
  "providers": { "openrouter": { "apiKey": "sk-..." } },
  "agents": { "defaults": { "model": "anthropic/claude-sonnet" } },
  "tools": { "web": { "search": { "apiKey": "BSA-..." } } }
}

In MALDA scripts, use getMaldaConfig() to read this config as an object (or null if the file is missing). See Built-in Functions for getMaldaHome() and getMaldaConfig().

32.3.1 agents.memory schema

The assistant reads agents.memory for GraphMemory behavior (embedding, reflection, KB indexing, and retention).

{
  "agents": {
    "memory": {
      "embed": "hash",
      "modelPath": "",
      "pruneEpisodicAfterDays": 30,
      "consolidateMinEpisodic": 3,
      "maxNodes": 5000,
      "reflectEnabled": false,
      "reflectMinEpisodic": 3,
      "reflectEveryNSaves": 1,
      "reflectModel": "",
      "reflectMinConfidence": 0.7,
      "kbDir": "",
      "kbPattern": "**/*.md",
      "scopeParent": "project:myapp",
      "scopeHierarchy": ["project:myapp", "org:acme", "global"],
      "rerankMode": "onnx",
      "rerankModelPath": "~/.malda/models/cross-encoder"
    }
  }
}

32.4 Selecting OpenRouter vs local llama.cpp

The default assistant can use either OpenRouter (remote) or a local llama.cpp-based model. The backend is controlled by agents.defaults.backend in config.json and can be overridden per run with MALDA_AGENT_BACKEND or a CLI flag.

Extended structure:

{
  "providers": {
    "openrouter": {
      "apiKey": "sk-...",
      "model": "anthropic/claude-sonnet"
    },
    "local_llama": {
      "modelPath": "C:/Users/YourName/AppData/Local/MaldaLang/Models/default/qwen2.5-0.5b-instruct-q4_k_m.gguf",
      "contextLength": 4096,
      "gpuLayers": 0,
      "temperature": 0.7,
      "maxTokens": 2000
    }
  },
  "agents": {
    "defaults": {
      "backend": "openrouter",   // or "local-llama"
      "model": "anthropic/claude-sonnet"
    }
  },
  "tools": { "web": { "search": { "apiKey": "BSA-..." } } }
}

32.5 Default assistant behavior

The default assistant script (e.g. Examples/Assistant/assistant.malda) does the following:

You can override the script by setting MALDA_AGENT_SCRIPT to the path of your own .malda file or by placing assistant.malda in ~/.malda/.

32.6 Scheduling on Windows (Task Scheduler)

malda cron add/list/remove store job definitions in %USERPROFILE%\.malda\cron.json. MALDA does not run them itself, but on Windows you can either use malda cron install to create tasks automatically, or configure Task Scheduler manually.

32.5.0 Automatic installation (malda cron install)

To sync all jobs from %USERPROFILE%\.malda\cron.json into Windows Task Scheduler, run:

malda cron install

This command:

Only a small subset of cron expressions is supported for automatic mapping:

Cron expressionMeaningTask Scheduler trigger
0 9 * * *9:00 AM every day/SC DAILY /ST 09:00
0 18 * * *6:00 PM every day/SC DAILY /ST 18:00
0 9 * * 1-59:00 AM Mon–Fri/SC WEEKLY /D MON,TUE,WED,THU,FRI /ST 09:00

The in-process malda gateway scheduler also supports */N minute intervals, comma-separated hours (0 9,18 * * *), monthly (0 9 1 * *), and multi-weekday (0 9 * * 1,3,5) expressions.

32.5.1 Add the job in MALDA

Record the message and schedule so you can reuse the message when creating the task:

malda cron add --name "daily" --message "Good morning! What's on my calendar today?" --cron "0 9 * * *"

Note the job id and the exact message; you will use the same message in the scheduled task.

32.5.2 Find malda.exe

Task Scheduler needs the full path to the MALDA executable. If you run from the repo with dotnet run, the executable is under the project output, e.g.:

From PowerShell you can run where.exe malda if malda is on your PATH; otherwise use the path above. Use this full path as the program in the task.

32.5.3 Create the scheduled task (GUI)

  1. Press Win + R, type taskschd.msc, press Enter.
  2. Click Create Task (not “Create Basic Task” so you can set a daily trigger at a specific time).
  3. General tab: name the task (e.g. “MALDA daily assistant”). Choose “Run whether user is logged on or not” or “Run only when user is logged on” as needed.
  4. Triggers tab → New: set Daily and the time (e.g. 9:00 AM for cron 0 9 * * *).
  5. Actions tab → New:
    • Program/script: full path to malda.exe (e.g. C:\Users\You\Documents\maldalang\MaldaLang\bin\Debug\net8.0\malda.exe).
    • Add arguments: agent -m "Good morning! What's on my calendar today?" (use the exact message from malda cron add; escape or use single quotes if the message contains double quotes).
  6. Start in (optional): set to the folder where MALDA can find the assistant script (e.g. the repo root so Examples/Assistant/assistant.malda is found).
  7. Click OK to save. Create one task per scheduled message (e.g. one for 9:00, one for 18:00).

32.5.4 Create the scheduled task (command line)

Using schtasks to create a daily task at 9:00 AM:

schtasks /Create /TN "MALDA daily" /TR "\"C:\Path\To\malda.exe\" agent -m \"Good morning! What's on my calendar today?\"" /SC DAILY /ST 09:00 /RU "%USERNAME%"

Replace C:\Path\To\malda.exe with your actual malda.exe path and the message with the one you stored in malda cron add. /RU %USERNAME% runs the task as your user so it can read %USERPROFILE%\.malda and your config.

32.5.5 Environment and API key

The task runs in a clean environment. The assistant needs either:

32.5.6 Mapping cron expressions to Task Scheduler

MALDA stores cron expressions in %USERPROFILE%\.malda\cron.json and does not run them directly. You can either let malda cron install map supported patterns to Task Scheduler triggers automatically (see above), or translate them manually when creating tasks yourself:

Cron expressionMeaningTask Scheduler
0 9 * * *9:00 AM every dayTrigger: Daily, 9:00 AM
0 18 * * *6:00 PM every dayTrigger: Daily, 18:00
0 9 * * 1-59:00 AM Mon–FriTrigger: Daily, 9:00 AM, repeat weekly Mon–Fri (or use “Weekdays”)

Use malda cron add to define and list jobs, then either run malda cron install (Windows) or configure your system scheduler to run malda agent -m "message" at the matching times.

32.7 Skills

Skills are MALDA files in ~/.malda/skills/ that export tools (and optionally an agent) for the assistant. You can load them in two ways.

Static import

Use using Alias = skills.skillname to load ~/.malda/skills/skillname.malda and import its globals under the alias. For example:

using GithubSkill = skills.github;
// Then: GithubSkill.tools, GithubSkill.agent (if the skill exports them)

Dynamic loading

Use loadSkillsFromDir() to scan ~/.malda/skills/*.malda in one call, or getSkillNames() + loadSkill(name) for explicit control. Each loaded skill is an object with module globals plus a name field; failed loads include an error string. The default assistant uses loadSkillsFromDir(), adds each skill’s tools array to the agent, and registers each skill’s agent via addSubAgent when present.

var skills = loadSkillsFromDir();
for (var i = 0; i < skills.length; i++) {
  var s = skills[i];
  if (s.error != null && s.error != "") continue;
  if (s.tools != null) {
    for (var j = 0; j < s.tools.length; j++) agent.addTool(s.tools[j]);
  }
  if (s.agent != null) {
    var desc = s.agentDescription != null && s.agentDescription != ""
      ? s.agentDescription : "Delegates to the " + s.name + " skill specialist.";
    agent.addSubAgent(s.agent, desc);
  }
}

Skill file convention

A skill file should export at least a tools array. Optionally export agent (an Agent instance) and agentDescription (tool description shown to the orchestrator). malda onboard installs a working template at ~/.malda/skills/greeting.malda (tool + sub-agent). Example:

// ~/.malda/skills/greeting.malda (installed by malda onboard)
@Tool("greet_user", "Greets someone by name", "...")
function greetUserTool(args) { ... }
var tools = ["greet_user"];
var agentDescription = "Greets users by name.";
var agent = new Agent("GreetingSkill", "specialist", "...", skillClient);
agent.addTool("greet_user");

Place additional .malda files in ~/.malda/skills/. The assistant discovers and loads them automatically when using the default script. Run malda doctor to validate skill syntax.

32.8 Channels / Telegram

You can run the assistant over a channel so it communicates with users via an external transport. The same assistant script is used; the host injects a channel that supplies input (e.g. from Telegram) and sends print() output back to that channel.

Running over Telegram

To run the assistant as a Telegram bot:

  1. Create a bot with BotFather and obtain the bot token.
  2. Set the token via TELEGRAM_BOT_TOKEN or in ~/.malda/config.json under channels.telegram.botToken.
  3. Run malda agent -c telegram or malda agent --channel telegram.

The process stays running and uses long polling to receive messages. Each message you send to the bot is passed to the assistant as input(); the assistant’s reply (from print()) is sent back to the same chat. The same script (assistant.malda) and config (API keys, model, tools, memory) are used as for the console; only the source of input and the destination of output change.

Config example

{
  "providers": { "openrouter": { "apiKey": "sk-..." } },
  "agents": { "defaults": { "model": "anthropic/claude-sonnet" } },
  "channels": { "telegram": { "botToken": "123456:ABC-DEF..." } }
}

If the token is missing when you run malda agent -c telegram or malda gateway, the CLI prints an error and exits. Each Telegram chat gets its own memory scope (chat:{id}); global memories (no scope) remain visible in every chat. For a persistent bot with scheduled jobs, prefer malda gateway over malda agent -c telegram.

See Also