Language: English | 한국어
multi-model-code-agent is a small TypeScript CLI that gives you a Claude Code style workflow with pluggable backends.
This repository is part of a broader project: study the methodology visible in Claude Code's workflow and observable product behavior, adapt the parts that are genuinely useful, and turn that research into a vibe-coding tool that can work well across many different LLMs instead of being tied to one model or one vendor. The CLI in this repo is the practical testbed for that goal.
In other words, the project intentionally borrows many methodological ideas from Claude Code, especially around:
- a REPL-first coding workflow
- a tool-driven agent loop
- human approval around risky actions
- grounded repository analysis instead of pure model guesswork
- saved sessions, runtime switching, and iterative coding ergonomics
At the same time, the implementation here is not trying to clone Claude Code line by line. It is a separate multi-model implementation shaped around Ollama, OpenAI-compatible backends, Codex CLI, local-model behavior, and the long-term goal of making one coding tool work reliably with many different LLMs.
Current goals:
- Use local models through
Ollama - Use remote models through any
OpenAI-compatiblechat-completions API - Use
Codex CLIthrough a local ChatGPT login, without managing an API key in this project - Let the model call ten core coding tools:
summarize_projectfind_entrypointsummarize_configlist_filesread_fileread_multiple_filessearch_fileswrite_patchrun_filesrun_shell
- Keep dangerous actions behind human approval by default
- keep learning from Claude Code's methodology while validating which ideas still hold up when the backing model is not fixed
- use this CLI as a concrete stepping stone toward a broader multi-LLM vibe-coding tool
This is an MVP, so the focus is clarity and learnability over raw power.
docs/claude-code-inspiration.mdexplains what this project borrows conceptually from Claude Code and what it does not copy.docs/milestones.mdtracks the current roadmap and milestone definitions.docs/development-log.mdrecords important project changes, decisions, and known issues.docs/supported-runtime-matrix.mddefines which provider/model combinations are treated as primary, secondary, or experimental.docs/release-checklist.mdis the release-readiness checklist for this CLI repository.- Korean companions are available in:
README.ko.mddocs/claude-code-inspiration.ko.mddocs/milestones.ko.mddocs/development-log.ko.mddocs/supported-runtime-matrix.ko.mddocs/release-checklist.ko.md
The agent is made of five pieces:
Model adapterPrompt + JSON protocolTool registryAgent loopCLI / REPL
The model is told to respond with exactly one JSON object:
- Final answer:
{ "type": "message", "message": "..." }- Tool request:
{
"type": "tool_call",
"tool": "read_file",
"arguments": { "path": "src/index.ts" },
"thinking": "I need to inspect the entrypoint first."
}The CLI executes the tool, feeds the result back to the model, and repeats until the model returns a final answer.
npm installExamples:
ollama pull qwen2.5-coder:7b
ollama pull gemma3:12bPowerShell:
Copy-Item .env.example .envnpm run dev -- --provider ollama --model qwen2.5-coder:7b --workdir D:\your-projectOr use a locally logged-in codex CLI session:
npm run dev -- --provider codex --workdir D:\your-projectOr rely on .env:
npm run devIf you want a built CLI entrypoint instead of npm run dev, use:
npm run build
npm start -- --version
npm start -- --helpFor a local global install from this checkout:
npm run build
npm link
mm-agent --version
mm-agent --helpNotes:
- the CLI command name is
mm-agent - the built entrypoint is
dist/index.js - the built CLI now includes a
#!/usr/bin/env nodeshebang so it can be launched as a real command afternpm linkornpm install -g . package.jsonis still markedprivate, so this is a local install/release-readiness path, not an npm publish workflow yet- run
npm run smoke:packagingto verify the built CLI entrypoint and--helppath - run
npm run smoke:releasefor the tighter release-readiness gate used for CLI closeout - run
npm run smoke:closeoutto execute the scripted release gate plus the current-provider live smoke path in one step - see
docs/release-checklist.mdfor the full manual + scripted release gate
The current CLI project does not claim universal support for every model that can fit an adapter.
The primary day-to-day supported paths are:
ollamawithqwen3-coder:30bon Windowscodexwithgpt-5.4on Windows
Secondary compatibility support exists for OpenAI-compatible backends and nearby local coding families such as Qwen2.5 or Gemma, but the current release bar is centered on the two primary paths above.
See docs/supported-runtime-matrix.md for the current support tiers and release assumptions.
/help/help runtime|sessions|profiles|models|safety/?and/? <topic>as a short alias for/help/config/status/history [count]/history latest [count]/history <session-id> [count]/resume [count]/resume latest [count]/resume <session-id> [count]/resume runtime latest [count]/resume runtime <session-id> [count]/sessions [count]/sessions summary <current|latest|session-id> [count]/sessions compare [count]/sessions compare all [count]/sessions search <query> [count]/sessions delete <session-id>/sessions clear-idle [count]/sessions prune <keep-count>/profiles/profiles search <query>/profiles diff <name>/profiles save <name>/profiles rename <old-name> --to <new-name>/profiles load <name>/profiles delete <name>/session [count]/profile/title <text>/tools/reset/provider ollama|openai|codexpersists to.env/model <name>persists to.env/model defaultresets to the provider default/models [current|all|provider]shows model choices/models [current|all|provider] search <query>filters model names and shows family hints/models [current|all|provider] doctorchecks provider readiness and common failure causes/models [current|all|provider] smoke [quick|protocol|all]runs live provider checks for plain replies and/or structured JSON envelopes/base-url <url>persists to.env/api-key <value>/workdir <path>/temperature <value|default>/max-turns <value|default>/request-timeout <seconds|default>/approve on|off/quit
If you mistype a slash command, the REPL now suggests the closest known command and a matching help topic when possible.
Recent CLI output polish:
- tool summaries now use a more consistent
tool_name SUCCESS:/tool_name FAILED:style run_shellandrun_filesresults keep the detailed body output, but the first summary line is shorter and easier to scan
Run the smoke test to check the minimum healthy path for the project:
npm run smokeThis runs:
npm run typechecknpm run build- a project-structure prompt check
- an entrypoint-flow prompt check
- a config-summary prompt check
- a workspace-local file-creation check
- a
.envpersistence check - a path-boundary regression check
- a session-history persistence and redaction check
- a model-catalog search and family-hint regression check
- a provider adapter retry/fallback regression check
- a built-CLI packaging check (
dist/index.js, shebang, and--help) - a provider-readiness doctor regression check
- a live-provider smoke-matrix regression check
- a JSON/tool-call normalization regression check
For release-readiness instead of the full broad smoke chain, use:
npm run smoke:releaseOr use the scripted closeout path that also runs the current-provider live smoke:
npm run smoke:closeoutThat tighter gate runs:
npm run typechecknpm run buildnpm run smoke:packagingnpm run smoke:approvalsnpm run smoke:replnpm run smoke:modelsnpm run smoke:live-matrix
For a focused shell-selection regression check, run:
npm run smoke:shellsEach REPL session now writes a small JSONL log so you can inspect recent activity with /history and browse older sessions with /sessions.
- default location:
%USERPROFILE%\\.multi-model-code-agent\\sessions - override location: set
MM_AGENT_HOME - sensitive values such as
/api-key ...are redacted before they are written - use
/sessionsto list recent saved session ids - use
/sessions compareto compare the latest non-idle sessions by message count, command count, config changes, and a simple activity profile - use
/sessions compare allif you also want to include idle startup-only sessions in the comparison view - use
/sessions summary currentto get a focused summary of the current saved session - use
/sessions summary latestor/sessions summary <session-id>to inspect one saved session before resuming it - use
/sessions search <query>or/sessions find <query>to filter saved sessions by title, provider, model, workdir, or reason /sessions searchnow also matches saved user/assistant text and shows a shortmatch:preview line- use
/sessions delete <session-id>to remove one saved session by full or unique-prefix id - use
/sessions clear-idleto remove idle startup-only sessions, oldest first - use
/sessions prune <keep-count>to keep only the latest saved sessions and delete older ones after confirmation - use
/title <text>to override the current session title with something easier to recognize later /sessionis a short alias for/sessions/sessionsnow shows a short title from the first saved user prompt and the last activity time, so similar sessions are easier to tell apart- use
/history latestto inspect the most recent earlier session - use
/history <session-id>to open a specific saved session by full or unique prefix id - use
/resume latestto replace the current conversation with messages from the most recent earlier session - use
/resume <session-id>to continue from a specific saved session by full or unique prefix id /resumeonly restores saved user/assistant messages; your current provider, model, and workdir stay as they are- use
/resume runtime latestor/resume runtime <session-id>to restore the saved provider, model, workdir, and runtime flags together with the conversation /resumenow prints a short context recap with the saved session title, last active time, activity profile, and the last visible user/assistant messages- use
/statusto see the current runtime config together with the current saved session id, resume source, activity profile, and latest visible messages - corrupted or schema-invalid session logs are skipped during browsing with a visible warning
- exact full session ids are resolved directly, even when they are older than the recent-session scan window
- use
/profiles save <name>to store the current provider, model, base URL, workdir, and runtime flags as a reusable profile - use
/profilesto list saved profiles and see which one matches the current runtime - use
/profiles search <query>to filter saved profiles by name, provider, model, base URL, or workdir - use
/profiles diff <name>to see what would change before loading a saved profile - use
/profiles rename <old-name> --to <new-name>to rename a saved profile without recreating it - use
/profiles load <name>to preview the changes, confirm them, and then restore a saved profile into the current runtime - use
/profiles delete <name>to remove a saved profile after confirmation /statusnow also shows which saved profiles match the current runtime exactly- profiles do not store API keys; use
/api-keyseparately if needed /profileis a short alias for/profiles- runtime-changing commands now run a small readiness preflight first, so provider/model/profile/runtime switches can warn before the next request fails
- saved profiles now also preserve the request timeout for slow local or remote model paths
Summarize this project structure in Korean.Find the main entrypoint of this project and explain the execution flow in Korean.Read package.json and README.md, then explain how to run this project.Search for all files related to config parsing and summarize them.
The agent now has deterministic repo-analysis helpers:
summarize_projectfind_entrypointsummarize_config
These tools make structure, entrypoint, and config questions more reliable, especially when smaller local models struggle to stay grounded.
If your provider exposes an OpenAI-compatible /chat/completions endpoint, you can run:
npm run dev -- --provider openai --model your-model-name --base-url https://api.example/v1Then set OPENAI_API_KEY in .env, or use /api-key ... inside the REPL.
If you want to use codex without managing an API key in this project, install the OpenAI Codex CLI, sign in once, and use the codex provider:
codex login
npm run dev -- --provider codex --workdir D:\your-projectNotes:
codex login statusshould show that you are logged in with ChatGPT/base-urland/api-keyare ignored for thecodexprovider/modelstill works and is passed through tocodex exec -m .../model defaultclears the explicit model and goes back to the Codex account default
The project now keeps per-provider model preferences so switching providers does not drag an old model along:
OLLAMA_MODEL_NAMEOPENAI_MODEL_NAMECODEX_MODEL_NAME
MODEL_NAME is now treated as a deprecated legacy fallback. New writes clear it, and provider-specific keys are the source of truth.
Inside the REPL you can inspect model choices with:
/models
/models all
/models ollama
/models openai
/models codex
/models search qwen
/models codex search gpt-5
/models doctor
/models all doctor
/models smoke
/models all smoke protocol
/models codex smoke quick
Behavior by provider:
ollama: reads your locally installed models fromollama listopenai: fetches a live list from/modelswhenOPENAI_API_KEYis setcodex: shows the provider default and explains that Codex CLI does not expose a live account model list
Search behavior:
/models ... search <query>filters the visible model names before rendering- filtered results also include short family hints for well-known choices such as Qwen coder, Gemma, GPT-5.4, and Codex-oriented models
Doctor behavior:
/models ... doctorchecks the selected provider scope for common setup failuresollamadoctor checks the localollama listcommand, base URL shape, and whether the expected model is installedopenaidoctor checks base URL shape, whether an API key is configured, and whether/modelsis reachablecodexdoctor checks Codex CLI availability and ChatGPT login status- runtime request failures are also classified by provider, so auth/model/base-url/login/time-out issues return clearer next steps instead of one generic error
- provider/model/profile/runtime switches now run a readiness preflight before the new runtime is applied
/provider,/model, and/base-urlprint preflight warnings immediately when the next runtime looks risky/base-urlnow trims common endpoint suffixes like/chat/completions,/responses,/models, or Ollama/api/chatback to the provider base URL automatically
Live smoke behavior:
/models ... smoke [quick|protocol|all]can check a plainOKreply, a structured JSON/message envelope, or both in one pass- providers with obvious blocking readiness issues are skipped before the live request runs, and the output shows why
- use
npm run smoke:live -- current,npm run smoke:live -- all protocol, ornpm run smoke:live -- codex quickfor the same live matrix outside the REPL /profiles loadand/resume runtimefold the same preflight into their preview/confirm flow before they reset the conversation
Session tuning:
/temperature <value|default>updates the current session sampling temperature without rewriting.env/max-turns <value|default>updates the current session turn budget without restarting the REPL/request-timeout <seconds|default>updates the current session request timeout for slow providers without rewriting.env- these settings are included if you later save the current runtime as a profile
Model-specific prompt tuning:
- the system prompt now adapts its operating guidance by provider/model family
- local
QwenandGemmapaths are pushed toward smaller grounded steps and more deterministic helper usage codexgets shorter execution-oriented guidance for larger cross-file workopenai-compatiblemodels get extra diagnostics-oriented guidance around API key, base URL, and live model mismatches- the agent also retries once when a provider returns an empty or obviously placeholder-like final answer before surfacing a fallback
- the agent retries once when a reply looks like a broken
tool_call/ structured envelope instead of surfacing that malformed payload directly
write_patchrequires approval unless auto-approve is onrun_shellrequires approval unless auto-approve is on- file access is restricted to the chosen
workdir - creating new files and nested folders inside
workdiris allowed
run_shell accepts an optional shell field:
default: use the runtime default shellcmd: forcecmd.exeon Windowspowershell: force PowerShell on Windows
This is useful when a command is shell-specific. For example, Start-Process ... should be run with shell: "powershell" instead of the default Windows shell behavior.
On Windows, run_shell can also retry once in PowerShell after a failed default/cmd attempt when the command clearly looks PowerShell-specific or when a start "" ... launch is a better fit for Start-Process.
If you already know a command is PowerShell-specific, setting shell: "powershell" is still the most direct option. A good pattern for Python GUI scripts is:
{
"command": "$cmd = Get-Command pyw, pythonw, py, python -ErrorAction SilentlyContinue | Select-Object -First 1; if (-not $cmd) { throw 'Python launcher not found' }; Start-Process $cmd.Source -ArgumentList 'test\\hello.py'",
"timeoutMs": 10000,
"shell": "powershell"
}If the user asks to run or launch existing example/source files, the agent can now use run_files instead of building a large ad-hoc shell script.
Supported file types:
- JavaScript:
.js,.mjs,.cjs - Python:
.py - C:
.c - C++:
.cpp,.cc,.cxx - Rust:
.rs - Java:
.java - HTML:
.html,.htm
Typical patterns:
{ "paths": ["test/hello.js", "test/hello.py"], "timeoutMs": 30000 }{
"directory": "test",
"nameContains": "hello",
"extensions": [".js", ".py", ".c", ".cpp", ".rs", ".java", ".html"],
"recursive": true,
"maxFiles": 12,
"timeoutMs": 30000
}write_patch approvals now show a small diff-style preview before you confirm:
- for
replace, the file path, match count, first match line, and a compact+/-diff hunk - for
create, the target path, whether overwrite is on, and a compact added-lines preview write_patch,run_shell, andrun_filesapprovals now use a shorter field-style layout socwd, timeout, shell/path scope, and diff previews are easier to scan quickly- session/profile status-style outputs now group information into short sections (
Session,Runtime,Activity,Conversation) so longer command results are easier to scan
If the user asks to create files inside the current workspace, the agent should use write_patch instead of refusing the request.
This is the first step of Milestone 2, which focuses on safer and more understandable edits.
src/index.tsCLI + REPLsrc/config.tsenv and CLI argument parsingsrc/modelAdapters.tsOllama, OpenAI-compatible, and Codex CLI clientssrc/repoAnalysis.tsdeterministic repo analysis helperssrc/prompt.tssystem prompt and tool contractsrc/tools.tscoding toolssrc/agent.tstool loop