The config.json file
Reasonix reads a single global config from ~/.reasonix/config.json
(Windows: %USERPROFILE%\.reasonix\config.json). The file is created
automatically on first run; you can hand-edit it any time. The CLI flag
--no-config bypasses it, useful in CI.
Per-project overrides live under <project>/.reasonix/ —
skills, memory, settings.json (hooks). Project scope wins over global on name
collision.
Top-level keys
{
"apiKey": "sk-...",
"baseUrl": "https://api.deepseek.com",
"lang": "en", # UI language: en | zh
"preset": "auto", # auto | flash | pro
"editMode": "review", # review | auto | yolo
"reasoningEffort": "high", # high | max
"theme": "auto", # light | dark | auto
"search": false, # enable web_search/web_fetch tools
"webSearchEngine": "mojeek", # mojeek | searxng
"webSearchEndpoint": "http://localhost:8080",
"mcp": [], # MCP server specs
"mcpDisabled": [], # names skipped at startup
"projects": { # per-workspace overrides
"/abs/path": {
"shellAllowed": ["npm", "git status"]
}
},
"semantic": { ... }, # embedding provider for `reasonix index`
"session": null
}
editMode is the single trust dial for an entire session.
review queues edits + gates shell. auto applies
edits + still gates shell. yolo skips both gates — only use
inside a sandbox.
MCP servers
Reasonix speaks the Model Context Protocol natively. Every entry in
config.mcp is a single string — the same format the
--mcp CLI flag accepts — so one parser handles both. Three
transports are supported.
Stdio (subprocess)
{
"mcp": [
"fs=npx -y @modelcontextprotocol/server-filesystem /tmp",
"git=uvx mcp-server-git --repository ."
]
}
Format: name=command arg1 arg2. The name= prefix
namespaces every tool the server exposes. Args use shell-style splitting;
quote any with spaces.
SSE (HTTP)
{
"mcp": [
"remote=https://example.com/mcp/sse",
"https://other.example.com/mcp"
]
}
Plain http:// / https:// URLs use HTTP+SSE for
back-compat. Anonymous (no name=) entries work but can't be
toggled by name later.
Streamable HTTP (2025-03 spec)
{
"mcp": [
"edge=streamable+https://edge.example.com/mcp"
]
}
Opt in with the streamable+ URL prefix.
CLI flags & slash commands
npx reasonix code --mcp "fs=npx -y @mcp/server-filesystem /tmp"
npx reasonix mcp inspect "git=uvx mcp-server-git"
npx reasonix mcp list
| Command | What it does |
|---|---|
/mcp |
Open the interactive MCP hub. |
/mcp disable <name> |
Persist to mcpDisabled; effective on next launch.
|
/mcp enable <name> |
Re-enable a disabled server. |
/mcp reconnect <name> |
Reconnect a live server and pick up newly-registered tools. |
Skills
A skill is a markdown playbook the model can invoke (/skill <name>).
Names + descriptions are pinned in the prompt; bodies load on demand. Project
skills override global ones with the same name.
Layout
~/.reasonix/skills/ # global
audit-logs.md
refactor-react/
SKILL.md
<project>/.reasonix/skills/ # project (overrides global)
release-notes.md
Two equivalent shapes: a flat <name>.md, or a
<name>/SKILL.md folder when you want to colocate
attachments.
Frontmatter
---
name: audit-logs
description: Review git log for security red flags.
runAs: inline # inline | subagent
allowed-tools: bash,read # subagent tool allowlist
model: deepseek-chat # subagent model override
---
## Task
1. Fetch the last 20 commits.
2. Flag commits whose message mentions password / secret / token.
3. Report findings.
-
name1–64 chars: alnum,_,-, interior.. Defaults to filename stem. -
descriptionOne line. Shown in/skill list. -
runAsinline(default): body enters parent log.subagent: isolated child loop, only the final answer returns. -
allowed-toolsComma-separated literal tool names. Subagent only — scopes the child's tool registry. -
modelSubagent only. Must start withdeepseek-; ignored otherwise.
Slash commands
/skill list |
List every skill, scope-tagged. |
/skill new <name> |
Scaffold a stub at project scope. Add --global for
~/.reasonix/skills.
|
/skill show <name> |
Print the full body. |
/skill <name> [args] |
Run it. Args are appended to the body as a single string. |
Memory
Memory is user-private knowledge pinned into the immutable prefix — so the
agent reads it on every turn without re-priming. Two scopes: global
(cross-project facts about you) and project (per-workspace context).
Distinct from a committable REASONIX.md, which lives in the repo.
Layout
~/.reasonix/memory/
global/
MEMORY.md # index — pinned into the prefix
user_role.md
feedback_terse_comments.md
<project-hash>/ # sha1(absRoot)[0..16]
MEMORY.md
project_release_freeze.md
Entry shape
---
name: user_role
description: User is a senior backend engineer; new to React.
type: user # user | feedback | project | reference
scope: global
created: 2026-05-09
---
Body — the actual remembered fact, in plain markdown.
Types: user (who they are),
feedback (corrections / preferences),
project (initiative / deadline / motivation),
reference (where to look in external systems).
Slash commands
/memory list |
List all entries, both scopes. |
/memory show <name> |
Display body. Scope is auto-resolved. |
/memory forget <name> |
Delete one entry. |
/memory clear <scope> confirm |
Wipe an entire scope. confirm is mandatory.
|
Writing memories: say it in chat ("remember I prefer
Vitest over Jest"). The model invokes the scaffold_memory tool,
which proposes a file and waits for your /apply.
Hooks
Hooks are shell commands the harness fires on lifecycle events. Configured
in settings.json, not config.json. Project scope
first, then global.
Where to put them
<project>/.reasonix/settings.json # project scope
~/.reasonix/settings.json # global scope
Shape
{
"hooks": {
"PreToolUse": [
{
"command": "node scripts/audit.js",
"match": "^(write|edit_file|bash)$",
"description": "Audit risky tool calls before they run",
"timeout": 5000
}
],
"PostToolUse": [
{ "command": "echo done >> /tmp/reasonix.log" }
],
"UserPromptSubmit": [],
"Stop": []
}
}
Events
-
PreToolUseBefore a tool runs. Gating: exit 2 blocks; exit 0 passes. 5 s default timeout. -
PostToolUseAfter a tool runs. Non-gating; warn-only on non-zero. 30 s default. -
UserPromptSubmitBefore user input is processed. Gating (exit 2 blocks the message). -
StopOn/quitor session exit. Non-gating.
Stdin payload
Each hook receives a JSON object on stdin describing the event:
{
"event": "PreToolUse",
"cwd": "/workspace",
"toolName": "bash",
"toolArgs": { "command": "rm -rf /" },
"turn": 3
}
Permissions
Shell commands are gated per-workspace. The first time the agent runs a
command, you get an interactive allow once / allow always / deny
prompt; "allow always" persists the exact prefix to config.json
under that project.
{
"projects": {
"/abs/path/to/repo": {
"shellAllowed": [
"npm test",
"git status",
"ls"
]
}
}
}
Exact match after trim. git alone does
not cover git push origin main; list each prefix you
actually want green-lit.
/permissions list |
Show this project's allowlist. |
/permissions add <prefix> |
Add a shell prefix. |
/permissions rm <prefix|index> |
Remove by name or list index. |
/permissions clear confirm |
Wipe everything. confirm is mandatory. |
Web search
web_search + web_fetch ship in the box. Default
backend is Mojeek (no setup); switch to a self-hosted
SearXNG when you want full control over upstream engines.
/search-engine mojeek
/search-engine searxng # http://localhost:8080
/search-engine searxng http://192.168.1.5:8888
Equivalent config.json:
{
"webSearchEngine": "searxng",
"webSearchEndpoint": "http://localhost:8080"
}
Start a local SearXNG:
podman run -d --replace --name searxng -p 8080:8080 docker.io/searxng/searxng
Semantic index
reasonix index builds an embedding index the agent can query.
Pick an embedding provider:
{
"semantic": {
"provider": "ollama",
"ollama": {
"baseUrl": "http://localhost:11434",
"model": "nomic-embed-text"
},
"openaiCompat": {
"baseUrl": "https://api.example.com/v1",
"apiKey": "...",
"model": "text-embedding-3-small"
}
}
}
Switch by changing provider. Local Ollama is free and
air-gapped; OpenAI-compat lets you point at any hosted embedding API.
Still stuck?
Open a discussion or drop into good first issue. Every avatar
on the contributors wall started somewhere.