devkit Tiếng Việt

AI agents (MCP)

devkit mcp is an MCP server on stdin and stdout. Your agent starts it at the beginning of a session and it exits when the session ends. Every tool calls the same code as the CLI command it mirrors and returns the same JSON as that command with --json, so an agent can start sites, create lanes, run tests and read logs exactly as you would, without guessing ports or paths.

Set up your agent

devkit mcp config <agent> prints the exact command or config entry, with the absolute path of the devkit you ran (apps started from the Dock or a launcher do not get your shell's PATH, so a bare devkit would not be found). Without an agent it prints all of them. In the examples below <devkit> stands for that path, for instance /Applications/devkit.app/Contents/Helpers/devkit or ~/.local/bin/devkit.

--write merges the entry into the agent's config file instead: other servers and keys stay, an existing devkit entry is replaced, the previous file is kept as <file>.devkit-backup-<time>, and a JSON file with comments is refused rather than rewritten. For the agents configured per project, --dir <project> picks the project folder (default: the current one).

Claude Code

claude mcp add --scope project devkit -- <devkit> mcp

or devkit mcp config claude-code --write, which merges this into .mcp.json in the project:

{
  "mcpServers": {
    "devkit": { "type": "stdio", "command": "<devkit>", "args": ["mcp"] }
  }
}

Codex CLI

codex mcp add devkit -- <devkit> mcp

or devkit mcp config codex --write, which merges this into ~/.codex/config.toml ($CODEX_HOME/config.toml when set):

[mcp_servers.devkit]
command = "<devkit>"
args = ["mcp"]

Gemini CLI

gemini mcp add devkit <devkit> mcp

or devkit mcp config gemini --write, into .gemini/settings.json in the project:

{ "mcpServers": { "devkit": { "command": "<devkit>", "args": ["mcp"] } } }

Cursor

devkit mcp config cursor --write, into .cursor/mcp.json in the project:

{ "mcpServers": { "devkit": { "command": "<devkit>", "args": ["mcp"] } } }

VS Code (Copilot)

devkit mcp config vscode --write, into .vscode/mcp.json in the project. Note the key is servers:

{ "servers": { "devkit": { "type": "stdio", "command": "<devkit>", "args": ["mcp"] } } }

Claude Desktop

devkit mcp config claude-desktop --write, into ~/Library/Application Support/Claude/claude_desktop_config.json (Linux: ~/.config/Claude/). Restart Claude Desktop afterwards.

{ "mcpServers": { "devkit": { "command": "<devkit>", "args": ["mcp"] } } }

Any other MCP client

An MCP server on stdio, no environment needed:

{ "command": "<devkit>", "args": ["mcp"], "transport": "stdio" }

In the app

The MCP section has a pill per agent with its command or config and Copy. For Claude Code, Gemini CLI, Cursor and VS Code, Write to project… asks for the project folder and runs devkit mcp config <agent> --write --dir <folder>. When an agent connects, it appears under Connected, in the menu bar and in the status bar.

The tools

devkit mcp tools lists them with their group and description (--json adds the input schemas). Arguments are snake_case; a bad one is an INVALID_ARGUMENT result, not a protocol error.

GroupTools
status, doctorstatus (everything at once, checked live), doctor
stacksstack_list, stack_up, stack_restart, stack_logs, stack_down confirm
sitessite_list, site_link, site_park, site_set, site_action, site_clone, site_setup, site_hide, site_unhide, site_delete confirm, site_up, site_down, url
templatestemplate_get, template_set
xdebugxdebug_status, xdebug_set
processesproc_list, proc_start, proc_stop, proc_restart
exec, logsexec, logs
laneslane_list, lane_new, lane_up, lane_down, lane_rm confirm
databasesdb_snapshot, db_snapshot_list, db_restore confirm, db_snapshot_rm confirm, db_reset confirm, db_query
gitgit_status, git_checkout, git_fetch, git_pull, git_push (with_submodules, default true)
modulesmodules_status, modules_checkout, modules_pull, modules_push, modules_add (group, only)

A few worth knowing in detail:

exec
Runs a command in a site's or lane's folder with its PHP. command is an argv array such as ["php","artisan","migrate","--force"]; shortcut (artisan, composer or phpunit) puts php artisan, composer or php vendor/bin/phpunit in front of it. timeout_seconds defaults to 600, xdebug: true runs this one command with Xdebug. The output is the last 64 KiB; a failing command is still ok: true, with its exitCode.
url
Where a site or lane is served, whether it answers (one GET; a status below 500 is healthy), its Vite ports and the mail inbox URL. It works for a stopped site too.
logs
source is laravel (default), engine (the web server), proc:<name> or container:<service>; lines defaults to 200.
db_query
One read-only SELECT, SHOW, DESCRIBE or EXPLAIN in a read-only transaction, at most 500 rows (truncated says when there were more).
lane_new, site_clone, site_setup
Report each step as a progress notification when the agent asks for progress. Every tool given a progress token also reports "still running" every 10 seconds, and cancelling a call cancels the work (an exec is stopped, in a PHP container too).

Two things are deliberately not tools: devkit trust and devkit hosts sync, because they ask for your password.

Destructive tools and confirm

Six tools can destroy something: stack_down, site_delete, lane_rm, db_reset, db_restore and db_snapshot_rm. Called without "confirm": true they change nothing and return CONFIRM_REQUIRED describing exactly what would happen:

{"ok":false,"error":{"code":"CONFIRM_REQUIRED",
  "message":"this would remove lane core-development--crm-fix: stop it, drop its database core_development_l1 and its snapshots, remove its worktree …",
  "hint":"show this to the user; call lane_rm again with \"confirm\": true to go ahead"}}

A well-behaved agent shows you that text and asks before calling again with confirm. On top of that, the usual safety checks still apply with confirm: site_delete and lane_rm refuse with DIRTY_WORKTREE while there is uncommitted or unpushed work unless force is also true, and db_restore takes a safety snapshot unless safety is false. These tools are also marked with MCP's destructiveHint, so clients that ask before destructive calls do so.

The audit log

Every tool call is appended to ~/.config/devkit/audit.log as one JSON line: the time, the server's pid, the client (the name the agent reports for itself), the tool, its arguments, whether it only reads, ok or the error code, and how long it took. Secrets are replaced by [redacted] (template contents, password-like names, credentials in URLs). The log is rotated to audit.log.1 at 10 MB.

devkit mcp audit --limit 20
2026-10-26 14:31:07  claude-code  exec        ok                {"command":["php","vendor/bin/phpunit"],"site":"core-development--agent-a"}
2026-10-26 14:29:40  claude-code  lane_rm     CONFIRM_REQUIRED  {"lane":"core-development--old-spike"}
2026-10-26 14:22:13  claude-code  lane_new    ok                {"name":"agent-a","site":"core-development","start":true}

In the app, MCP → Audit log shows the same, reloaded when an agent makes a call. While a server runs, ~/.config/devkit/mcp/<pid>.json records which agent is connected, since when, and its last tool; devkit status lists these sessions and cleans up the files of servers that were killed.

Recommended workflows

One lane per agent

Never let two agents (or an agent and you) work in the same folder. Give each its own lane: a branch, a database and a port of its own.

Create a lane "agent-a" of core-development with lane_new (start: true),
work only in its folder, and run tests with exec on core-development--agent-a.

When the work is pushed, remove the lane with lane_rm; the agent will get CONFIRM_REQUIRED first and should show you what goes.

Tests and commands through exec

  • Ask the agent to run tests with exec on its lane (shortcut: "phpunit", or ["php","artisan","test"]) rather than its own shell, so the lane's PHP version and .env are used.
  • For one debug run, use exec with xdebug: true instead of turning Xdebug on for the site: Xdebug slows every request, and under caddy it is shared by every site on the container.
  • Let it read errors with logs (laravel, then proc:queue) and check data with db_query instead of opening a database shell.

Snapshots before risky steps

Before a migration or a data fix, have the agent call db_snapshot with a clear name (before_orders_migration). If things go wrong, db_restore needs your confirmation and keeps a safety snapshot of the broken state too.

Start with status and doctor

A good first instruction: "call status, then doctor for the site, and tell me what is running and what is broken before you change anything". Both read only.

What devkit guarantees

  • Nothing destructive without confirm. The six destructive tools only describe what they would do until called with "confirm": true.
  • No lost work by default. Deleting a site or removing a lane refuses while there is uncommitted or unpushed work, unless the agent also passes force. A restore keeps a safety snapshot.
  • No password prompts. Trusting certificates and editing /etc/hosts are not tools. Git runs with your existing credentials and never prompts.
  • Read-only queries are read-only. db_query refuses anything but one read statement and runs it in a read-only transaction.
  • Everything is recorded in the audit log on your machine, with secrets removed.
  • Nothing leaves your machine. devkit has no account and no telemetry; the MCP server talks only to the agent that started it.
devkit protects devkit's operations. An agent that also has a shell can still run rm or git push --force itself; use your agent's own permission settings for that.