New:Microsoft Teams Notifications Are Now Available in Socket.Learn more
Get Started

@mafdet/cli

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mafdet/cli

Mafdet AI command line — model calls, account queries, and a permissioned local agent.

latest
npmnpm
Version
1.4.29
Version published
Weekly downloads
29
-86.57%
Maintainers
1
Weekly downloads
 
Created
Source

@mafdet/cli

The official Mafdet AI command line: model calls, account queries, and a permissioned local agent.

0.4.13. 中文版见 README.zh-CN.md. The CLI never advertises a command it cannot serve, so mafdet help always lists exactly what works.

macOS and Windows are not yet verified. On Windows the command timeout uses taskkill /T, which is written but has never been run on a real Windows machine - so whether every grandchild process is reached there is unverified rather than fixed.

What Mafdet AI is

Mafdet AI is an OpenAI-compatible AI gateway: one API key and one base URL reach models from several providers, billed by usage. Any tool or SDK that speaks the OpenAI API works by pointing its base URL and key at Mafdet AI.

  • Base URL: https://api.mafdet.ai/v1
  • Endpoints: /chat/completions, /embeddings, /audio/speech
  • Providers: Google (Gemini), Kimi (Moonshot), Qwen, DeepSeek
  • 30 models as of August 2026. The catalogue changes, so the authoritative list with current prices is models.json
  • Docs: https://docs.mafdet.ai

Requirements

Node.js 20 or newer, and a Mafdet API key.

Install

npm install -g @mafdet/cli

Or build it from this repository:

pnpm --filter @mafdet/cli build
cd packages/cli && npm pack          # -> mafdet-cli-0.4.13.tgz
npm install -g ./mafdet-cli-0.4.13.tgz

The interactive session

Run mafdet with no arguments in a terminal and it opens a session: pick how to authenticate, choose a model, then talk to the agent.

mafdet                       # read-only
mafdet --allow-write         # changes are shown as a diff and confirmed first
mafdet --allow-command "pnpm test"

It is the same agent as mafdet agent, drawn differently - the same tools, the same approvals, the same cost accounting. The flags mean exactly what they mean there, and a session given neither has no write or command tool loaded at all.

mafdet in a pipeline, under --json, in CI, or with --no-tui behaves exactly as it did in 0.3: usage on stderr, exit 2. Nothing that reads the CLI's output will start receiving a drawing.

Quickstart

export MAFDET_API_KEY="sk-mafdet-live-..."     # never passed as a flag
export MAFDET_MODEL="deepseek-v4-flash"

mafdet doctor                    # check key, endpoints, model, balance
mafdet models list               # what this key can actually call
mafdet chat "Explain TypeScript decorators"
mafdet account balance

PowerShell

$env:MAFDET_API_KEY = "sk-mafdet-live-..."
$env:MAFDET_MODEL   = "deepseek-v4-flash"

mafdet doctor
mafdet chat "Explain TypeScript decorators"

Everything the CLI prints is ASCII, so output stays readable on a console running a non-UTF-8 code page (the Windows PowerShell 5.1 default). Piping a prompt works too, but PowerShell pipes UTF-16 by default — prefer passing the prompt as an argument, or use --input <file>.

Commands

CommandWhat it does
mafdet doctorOne pass over key, endpoints, model, tool-calling, balance, workspace, git
mafdet models list [--surface chat|embeddings|speech] [--agent]Models this key can call, joined with catalogue metadata
mafdet models show <id>One model in detail, including whether the agent may drive it
mafdet chat [prompt] [--model] [--system <file>] [--input <file>] [--no-stream] [--quiet] [--save]Send a prompt; streams by default
mafdet agent "<goal>" [--allow-write] [--allow-command "<prefix>"]Local agent; read-only unless told otherwise
mafdet agent (no goal, needs a terminal)Interactive session
mafdet embed [text|<file>] --model <id> [--output <file>]Text to vector
mafdet speech [text|<file>] --model <id> --output <file> --voice <name>Text to an audio file
mafdet account balance|usage|subscriptionWallet, spend and plan (needs the account:read scope)
mafdet sessions list|show|usage|deleteConversations saved on this computer (never calls a model)
mafdet sessions usage <id> --refreshShow settled ledger figures alongside the local estimate
mafdet config listThe resolved settings and where each came from

--json on any query command emits one complete JSON document; --plain emits tab-separated rows with no header, for cut and awk.

What the agent may do

Read-only by default: list, search, read files, and git status / git diff. It cannot change anything.

--allow-write adds edit_file and create_file, and then:

  • every change is shown as a diff and confirmed first, with Enter meaning no;
  • a non-interactive run cannot write at all, even with the flag - the write tools are not offered to the model in the first place;
  • there is no flag that approves everything in advance.

--allow-command "<prefix>" adds run_command, unprompted for exactly those prefixes: pnpm test permits pnpm test --filter web but never pnpm publish. There is no shell - the command is split into argv, so pipes, redirects, ;, &&, backticks and $( ) are refused with an explanation rather than sanitised.

What approving a command means. It means allowing that program to run on your machine, as you. The workspace bounds which files the agent's own tools may touch; it is not a sandbox, and it does not bound the program. pnpm test can read your home directory, reach the network, or start something that outlives the run - because that is what running a program is. A short list of obviously destructive names is refused (sudo, su, doas, chown, shutdown, reboot, and invoking a program by path), but treat that as a guard against slips rather than as containment. Approve prefixes the way you would run the command yourself.

In a session: /model, /permissions, /diff, /cost, /compact, /exit.

Configuration

Resolution order: --model > MAFDET_MODEL > project config > user config > default. mafdet config list shows which one won.

VariableDefault
MAFDET_API_KEY(required)
MAFDET_MODELnone
MAFDET_BASE_URLhttps://api.mafdet.ai/v1
MAFDET_BACKEND_URLhttps://backend.mafdet.ai

User config lives at ~/.config/mafdet/config.json (Linux), ~/Library/Application Support/mafdet/config.json (macOS) or %APPDATA%\mafdet\config.json (Windows).

A project may carry .mafdet.json with model — and nothing else. Credentials and endpoints in a project file are rejected outright: cloning a repository must never change where your key is sent.

Exit codes

Scripts may branch on these; a value never changes meaning once released.

CodeMeaning
0Success
1General failure (including doctor reporting a failed check)
2Bad command line or configuration
3Authentication or permission failure
4Model or API unavailable
5Local permission denied
6Cancelled by the user
7Cost, time, or loop ceiling reached

Compatibility

If you build a script on this, here is what will and will not move.

Within a major version:

  • an exit code never changes meaning, and a code is never reused for something else;
  • a field in --json output keeps its name, type and meaning; new fields may be added, so parse by name and ignore what you do not know;
  • --plain keeps its column order and stays tab-separated with no header.

This is a 0.x release, so semver still permits a break in a minor bump. The intent is not to use that latitude, and any change will be listed in CHANGELOG.md; the promise becomes binding at 1.0.0.

Money is always an integer count of micro-USD, sent as a string in --json so that no parser rounds it. Do not read the human-formatted dollar figure.

Output streams

Results and machine-readable JSON go to stdout. Progress, warnings, summaries and diagnostics go to stderr, so mafdet chat ... > answer.txt captures the answer alone and mafdet models list --json | jq always parses.

Credentials

The key is read from MAFDET_API_KEY. There is deliberately no --api-key flag: it would put the key into shell history and the process list. Keys are never written to a config file and never printed in full — only as a fingerprint like sk-mafdet-live-<redacted>.

Saved conversations

Interactive sessions are saved on this computer, and only on this computer. They are not uploaded, and Mafdet holds no copy of them.

That is a statement about the transcript, not about the model. The messages you send are still sent to the API to be answered and still appear in your usage records; what stays local is the saved copy.

Where they live:

PlatformPath
Linux / WSL${XDG_STATE_HOME:-~/.local/state}/mafdet/sessions
macOS~/Library/Application Support/mafdet/sessions
Windows%LOCALAPPDATA%\mafdet\sessions

The files are plain text. A transcript contains your messages, the model's replies, and any source the agent read while working — so treat a session directory the way you would treat the project it came from. API keys are the one exception: everything is passed through redaction on the way to disk, so a key you paste into a prompt is stored as <redacted>. Files are created 0600 and directories 0700 on Linux and macOS; Windows has no equivalent mode bits and inherits the ACL of %LOCALAPPDATA%.

The agent cannot read these directories, even when you run mafdet from your home directory and the store is technically inside the workspace. Otherwise an agent working on one project could read another project's transcript in full.

Turning it off and cleaning up:

mafdet --no-history            # this run is not recorded at all
mafdet chat "..." --save       # a one-shot chat is saved only when asked
mafdet sessions list           # what is saved, and the path when nothing is
mafdet sessions delete <id> --yes

A single mafdet chat is not a conversation anyone resumes, so it is not recorded unless --save is given. --no-history still wins over --save, and a chat cancelled with Ctrl+C is not saved at all — half a reply is a worse record than none.

--no-history writes nothing — not an empty directory, not an index entry.

Deleting removes the local messages and this session's usage mapping. It does not remove API usage, billing records or charges: those belong to the API key, not to the transcript. And it is an ordinary file delete, not a secure erase — backups, snapshots and the filesystem itself may still hold copies.

Reconciling what a session cost

mafdet sessions usage <id> adds up what a conversation used from the local record. Those charges are estimates, computed with the gateway's own arithmetic but computed here.

--refresh asks the billing ledger for settled figures. It pages through the current API key's usage events for the session's time window; request IDs stay local and are used only to match returned rows. No messages, title, workspace or session ID are sent. Requests paid for by a different API key are left alone and reported, so you know to run it again with that key.

A request that the ledger has not caught up with stays pending, and a request that never returned an ID stays unknown. Neither is ever shown as 0, which would read as "it was free".

Cost and cancellation

chat prints tokens and an estimated charge to stderr, computed with the same arithmetic the gateway bills with. The wallet remains the authority.

Cancelling with Ctrl+C closes the connection. In testing against production a cancelled stream produced no charge, but that is an observation, not a guarantee: if the upstream has already finished generating, a charge can still land. The summary after a cancel is labelled partial: for that reason.

Keywords

mafdet

FAQs

Package last updated on 03 Sep 2026

Related posts