diff --git a/plugins/lfg/bin/lfg-command.ts b/plugins/lfg/bin/lfg-command.ts
index eecc3c8..b6eb8d9 100644
--- a/plugins/lfg/bin/lfg-command.ts
+++ b/plugins/lfg/bin/lfg-command.ts
@@ -1,5 +1,6 @@
 import { existsSync } from "node:fs"
 import { join } from "node:path"
+import { LAZYCODEX_INSTALLER_COMMAND } from "./lfg-installer"
 import type { JsonObject } from "./lfg-json"
 
 export const SUPPORTED_COMMANDS = ["status", "doctor", "lazycodex install", "lazycodex status", "setup install-plan", "setup show"] as const
@@ -14,7 +15,7 @@ export function unsupportedCommand(positional: readonly string[]): JsonObject {
     message: `lfg does not run ${command}; it only reports the lazycodex Codex adapter installer contract for grok-build.`,
     role: "lazycodex_adapter_installer",
     adapterPackage: "lazycodex-ai",
-    installerCommand: "npx lazycodex-ai install",
+    installerCommand: LAZYCODEX_INSTALLER_COMMAND,
     lfgIsPlugin: false,
     supportedCommands: [...SUPPORTED_COMMANDS],
   }
diff --git a/plugins/lfg/bin/lfg.test.ts b/plugins/lfg/bin/lfg.test.ts
index 295c8c6..1e456fe 100644
--- a/plugins/lfg/bin/lfg.test.ts
+++ b/plugins/lfg/bin/lfg.test.ts
@@ -1,5 +1,5 @@
 import { describe, expect, test } from "bun:test"
-import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises"
+import { chmod, mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises"
 import { tmpdir } from "node:os"
 import { join } from "node:path"
 
@@ -30,6 +30,37 @@ describe("lfg CLI", () => {
     expect(JSON.stringify(result.json)).not.toContain("grok_plugin")
   })
 
+  test("runs lazycodex installer through npx when explicitly requested", async () => {
+    const fakeBin = await makeFakeNpx(0)
+    const result = await runLfg(["--json", "lazycodex", "install", "--run"], { PATH: `${fakeBin}:${process.env.PATH ?? ""}` })
+
+    expect(result.exitCode).toBe(0)
+    expect(result.json).toMatchObject({
+      ok: true,
+      status: "installed",
+      executed: true,
+      installerCommand: "npx lazycodex-ai install",
+      installerArgs: ["lazycodex-ai", "install"],
+      exitCode: 0,
+    })
+    expect(JSON.stringify(result.json)).toContain("fake lazycodex install")
+  })
+
+  test("reports npx installer failure", async () => {
+    const fakeBin = await makeFakeNpx(7)
+    const result = await runLfg(["--json", "lazycodex", "install", "--run"], { PATH: `${fakeBin}:${process.env.PATH ?? ""}` })
+
+    expect(result.exitCode).toBe(1)
+    expect(result.json).toMatchObject({
+      ok: false,
+      status: "install_failed",
+      executed: true,
+      installerCommand: "npx lazycodex-ai install",
+      exitCode: 7,
+    })
+    expect(JSON.stringify(result.json)).toContain("fake lazycodex failure")
+  })
+
   test("status and setup describe lfg as adapter installer not plugin", async () => {
     const status = await runLfg(["--json", "status"])
     expect(status.exitCode).toBe(0)
@@ -108,3 +139,11 @@ async function makeAdapterRoot(): Promise<string> {
   await writeFile(join(root, ".mcp.json"), `${JSON.stringify({ mcpServers: {} })}\n`)
   return root
 }
+
+async function makeFakeNpx(exitCode: number): Promise<string> {
+  const bin = await mkdtemp(join(tmpdir(), "lfg-fake-npx."))
+  const body = exitCode === 0 ? "echo fake lazycodex install: $*" : "echo fake lazycodex failure: $* >&2"
+  await writeFile(join(bin, "npx"), `#!/usr/bin/env bash\n${body}\nexit ${exitCode}\n`)
+  await chmod(join(bin, "npx"), 0o755)
+  return bin
+}
diff --git a/plugins/lfg/bin/lfg.ts b/plugins/lfg/bin/lfg.ts
index d2512a7..619fea0 100644
--- a/plugins/lfg/bin/lfg.ts
+++ b/plugins/lfg/bin/lfg.ts
@@ -4,10 +4,11 @@ import { access, stat } from "node:fs/promises"
 import { homedir } from "node:os"
 import { join, resolve } from "node:path"
 import { commandPath, SUPPORTED_COMMANDS, unsupportedCommand } from "./lfg-command"
+import { LAZYCODEX_INSTALLER_COMMAND, runLazycodexInstaller } from "./lfg-installer"
 import { isRecord, readJson, readJsonObject, type JsonObject } from "./lfg-json"
 
 type LfgEnv = { readonly root: string; readonly data: string; readonly stateDir: string; readonly launcher: string }
-type ParsedArgs = { readonly json: boolean; readonly positional: readonly string[] }
+type ParsedArgs = { readonly json: boolean; readonly run: boolean; readonly positional: readonly string[] }
 type LazycodexAdapter = {
   readonly found: boolean
   readonly root: string
@@ -39,7 +40,7 @@ async function dispatch(args: ParsedArgs): Promise<unknown> {
   }
   if (command === "lazycodex") {
     if (!subcommand || subcommand === "status") return lazycodexStatus()
-    if (subcommand === "install") return lazycodexInstallPlan()
+    if (subcommand === "install") return args.run ? runLazycodexInstaller() : lazycodexInstallPlan()
   }
   if (command === "setup") {
     if (!subcommand || subcommand === "install-plan") return setupInstallPlan()
@@ -105,7 +106,7 @@ function lazycodexStatus(): JsonObject {
     role: "lazycodex_adapter_installer",
     adapterPackage: "lazycodex-ai",
     purpose: "Install lazycodex Codex adapter for grok-build",
-    primaryAction: "npx lazycodex-ai install",
+    primaryAction: LAZYCODEX_INSTALLER_COMMAND,
     grokBuildUse: true,
     lfgIsPlugin: false,
     adapter: detectLazycodexAdapter(),
@@ -121,7 +122,7 @@ function lazycodexInstallPlan(): JsonObject {
     command: "lazycodex install",
     role: "lazycodex_adapter_installer",
     adapterPackage: "lazycodex-ai",
-    installerCommand: "npx lazycodex-ai install",
+    installerCommand: LAZYCODEX_INSTALLER_COMMAND,
     mutatesGlobalConfig: false,
     grokBuildUse: true,
     lfgIsPlugin: false,
@@ -129,7 +130,7 @@ function lazycodexInstallPlan(): JsonObject {
     adapterManifest: adapter.manifest,
     adapter,
     steps: [
-      { id: "run_npm_installer", status: "pending", text: "Run npx lazycodex-ai install." },
+      { id: "run_npm_installer", status: "pending", text: `Run ${LAZYCODEX_INSTALLER_COMMAND}.` },
       { id: "use_lazycodex_adapter", status: "pending", text: `Use lazycodex adapter from ${adapter.root} when running grok-build.` },
       { id: "verify_lazycodex_adapter", status: "pending", text: "Confirm the lazycodex adapter exposes .codex-plugin/plugin.json, .mcp.json, and skills/." },
     ],
@@ -181,8 +182,8 @@ function resolveLfgEnv(): LfgEnv {
 }
 
 function parseArgs(argv: readonly string[]): ParsedArgs {
-  const positional = argv.filter((arg) => arg !== "--json")
-  return { json: argv.includes("--json"), positional }
+  const positional = argv.filter((arg) => arg !== "--json" && arg !== "--run")
+  return { json: argv.includes("--json"), run: argv.includes("--run"), positional }
 }
 
 function emit(value: unknown, json: boolean): void {
diff --git a/plugins/lfg/bin/auth-provider.sh b/plugins/lfg/bin/auth-provider.sh
deleted file mode 100755
index 2050b8b..0000000
--- a/plugins/lfg/bin/auth-provider.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env bash
-# auth-provider.sh - Minimal env-based auth provider for Grok Build
-# Phase 1: Environment variable based authentication
-
-set -e
-
-# Check if LFG_AUTH_TOKEN is set
-if [[ -z "${LFG_AUTH_TOKEN}" ]]; then
-    echo "Error: LFG_AUTH_TOKEN environment variable is required" >&2
-    exit 1
-fi
-
-# Output token (bare or JSON format based on LFG_AUTH_FORMAT)
-if [[ "${LFG_AUTH_FORMAT}" == "json" ]]; then
-    echo "{\"access_token\":\"${LFG_AUTH_TOKEN}\",\"refresh_token\":\"\",\"expires_in\":3600}"
-else
-    echo "${LFG_AUTH_TOKEN}"
-fi
-
-exit 0
\ No newline at end of file
diff --git a/plugins/lfg/bin/lfg b/plugins/lfg/bin/lfg
index fba68ec..771de79 100755
--- a/plugins/lfg/bin/lfg
+++ b/plugins/lfg/bin/lfg
@@ -1,9 +1,6 @@
 #!/usr/bin/env bash
 set -euo pipefail
 
-# lfg — primary / default binary for the LFG runtime (workflows, plugin, team helpers)
-# Installed to ~/.grok/bin/lfg and ~/.local/bin/lfg by scripts/install-lfg-symlink.sh
-
 SOURCE="$0"
 while [[ -L "$SOURCE" ]]; do
   DIR="$(CDPATH= cd -- "$(dirname -- "$SOURCE")" && pwd)"
@@ -14,7 +11,7 @@ SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$SOURCE")" && pwd)"
 
 if [[ -z "${GROK_PLUGIN_ROOT:-}" ]]; then
   CANDIDATE="$(CDPATH= cd -- "$SCRIPT_DIR/../.." && pwd)"
-  if [[ -f "$CANDIDATE/plugins/lfg/.grok-plugin/plugin.json" ]]; then
+  if [[ -f "$CANDIDATE/plugins/lfg/package.json" ]]; then
     export GROK_PLUGIN_ROOT="$CANDIDATE"
   else
     export GROK_PLUGIN_ROOT="$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)"
@@ -22,80 +19,10 @@ if [[ -z "${GROK_PLUGIN_ROOT:-}" ]]; then
 fi
 
 export GROK_PLUGIN_DATA="${GROK_PLUGIN_DATA:-$PWD/.lfg}"
-
 export LFG_LAUNCHER="lfg"
 
-grok_update_check() {
-  local grok_bin="$1"
-  [[ "${LFG_SKIP_GROK_UPDATE_CHECK:-}" == "1" ]] && return 0
-
-  local current_version=""
-  current_version="$("$grok_bin" --version 2>/dev/null || true)"
-
-  local check_output=""
-  if ! check_output="$("$grok_bin" update --check 2>&1)"; then
-    return 0
-  fi
-
-  local signal
-  signal="$(printf '%s' "$check_output" | tr '[:upper:]' '[:lower:]')"
-  case "$signal" in
-    *"update available"*|*"upgrade available"*|*"new version"*|*"out of date"*) ;;
-    *) return 0 ;;
-  esac
-
-  local answer="${LFG_GROK_UPDATE_CONFIRM:-}"
-  if [[ -z "$answer" ]]; then
-    if [[ ! -t 0 ]]; then
-      echo "lfg: Grok update available, skipping prompt because stdin is not interactive" >&2
-      return 0
-    fi
-    echo "lfg: Grok update available." >&2
-    [[ -n "$current_version" ]] && echo "lfg: current $current_version" >&2
-    [[ -n "$check_output" ]] && echo "$check_output" >&2
-    read -r -p "Update Grok and restart now? [y/N] " answer
-  fi
-
-  case "$answer" in
-    [yY]|[yY][eE][sS])
-      "$grok_bin" update
-      ;;
-    *)
-      echo "lfg: Grok update skipped" >&2
-      ;;
-  esac
-}
-
-lfg_export_grok_build_known_keywords() {
-  local state_dir="$GROK_PLUGIN_DATA/state"
-  local keyword_file="$state_dir/grok-build-known-keywords.json"
-  local keyword_ids=""
-  mkdir -p "$state_dir"
-
-  if bun "$SCRIPT_DIR/lfg.ts" --json grok-build keywords > "$keyword_file" 2>/dev/null; then
-    export LFG_GROK_BUILD_KNOWN_KEYWORDS_FILE="$keyword_file"
-  else
-    rm -f "$keyword_file"
-    return 0
-  fi
-
-  keyword_ids="$(bun "$SCRIPT_DIR/lfg.ts" grok-build keywords --ids 2>/dev/null | tr '\n' ' ' | sed 's/[[:space:]]*$//')"
-  if [[ -n "$keyword_ids" ]]; then
-    export LFG_GROK_BUILD_KNOWN_KEYWORDS="$keyword_ids"
-    echo "lfg: Known @agent keywords: $keyword_ids" >&2
-    echo "lfg: known keyword registry exported: $keyword_file" >&2
-  fi
-}
-
 if [[ $# -eq 0 ]]; then
-  if command -v grok >/dev/null 2>&1; then
-    GROK_BIN="$(command -v grok)"
-    grok_update_check "$GROK_BIN"
-    lfg_export_grok_build_known_keywords
-    exec "$GROK_BIN"
-  fi
-  echo "lfg: grok executable not found; install Grok CLI or run 'lfg status' for the runtime helper" >&2
-  exit 127
+  set -- status
 fi
 
 exec bun "$SCRIPT_DIR/lfg.ts" "$@"
diff --git a/plugins/lfg/bin/lfg-command.ts b/plugins/lfg/bin/lfg-command.ts
new file mode 100644
index 0000000..eecc3c8
--- /dev/null
+++ b/plugins/lfg/bin/lfg-command.ts
@@ -0,0 +1,30 @@
+import { existsSync } from "node:fs"
+import { join } from "node:path"
+import type { JsonObject } from "./lfg-json"
+
+export const SUPPORTED_COMMANDS = ["status", "doctor", "lazycodex install", "lazycodex status", "setup install-plan", "setup show"] as const
+
+export function unsupportedCommand(positional: readonly string[]): JsonObject {
+  const command = positional.join(" ") || "(empty)"
+  return {
+    ok: false,
+    status: "error",
+    code: "unsupported_command",
+    command,
+    message: `lfg does not run ${command}; it only reports the lazycodex Codex adapter installer contract for grok-build.`,
+    role: "lazycodex_adapter_installer",
+    adapterPackage: "lazycodex-ai",
+    installerCommand: "npx lazycodex-ai install",
+    lfgIsPlugin: false,
+    supportedCommands: [...SUPPORTED_COMMANDS],
+  }
+}
+
+export function commandPath(exe: string): string | null {
+  const pathValue = process.env.PATH ?? ""
+  for (const dir of pathValue.split(":")) {
+    const candidate = join(dir, exe)
+    if (existsSync(candidate)) return candidate
+  }
+  return null
+}
diff --git a/plugins/lfg/bin/lfg-json.ts b/plugins/lfg/bin/lfg-json.ts
new file mode 100644
index 0000000..2c3a841
--- /dev/null
+++ b/plugins/lfg/bin/lfg-json.ts
@@ -0,0 +1,21 @@
+import { readFile } from "node:fs/promises"
+
+export type JsonObject = { readonly [key: string]: unknown }
+
+export async function readJson(path: string, fallback: unknown): Promise<unknown> {
+  try {
+    return JSON.parse(await readFile(path, "utf8")) as unknown
+  } catch (error) {
+    if (error instanceof Error) return fallback
+    throw error
+  }
+}
+
+export async function readJsonObject(path: string): Promise<JsonObject> {
+  const parsed = await readJson(path, {})
+  return isRecord(parsed) ? parsed : {}
+}
+
+export function isRecord(value: unknown): value is Record<string, unknown> {
+  return typeof value === "object" && value !== null && !Array.isArray(value)
+}
diff --git a/plugins/lfg/bin/lfg-mcp.test.ts b/plugins/lfg/bin/lfg-mcp.test.ts
new file mode 100644
index 0000000..15025ca
--- /dev/null
+++ b/plugins/lfg/bin/lfg-mcp.test.ts
@@ -0,0 +1,26 @@
+import { describe, expect, test } from "bun:test"
+
+const MCP = new URL("lfg-mcp.ts", import.meta.url).pathname
+
+describe("lfg MCP", () => {
+  test("lists minimal tools and dispatches lazycodex install", async () => {
+    const proc = Bun.spawn(["bun", MCP], { stdin: "pipe", stdout: "pipe", stderr: "pipe" })
+    proc.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id: "tools", method: "tools/list" })}\n`)
+    proc.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id: "install", method: "tools/call", params: { name: "lazycodex", arguments: { action: "install" } } })}\n`)
+    proc.stdin.end()
+    const stdout = await new Response(proc.stdout).text()
+    const code = await proc.exited
+    expect(code).toBe(0)
+    const lines = stdout.trim().split("\n").map((line) => JSON.parse(line) as Record<string, unknown>)
+    expect(toolNames(lines[0])).toEqual(["status", "doctor", "lazycodex", "setup"])
+    expect(JSON.stringify(lines[1])).toContain("npx lazycodex-ai install")
+  })
+})
+
+function toolNames(response: Record<string, unknown> | undefined): string[] {
+  const result = response?.result
+  if (typeof result !== "object" || result === null || Array.isArray(result)) return []
+  const tools = (result as Record<string, unknown>).tools
+  if (!Array.isArray(tools)) return []
+  return tools.flatMap((tool) => typeof tool === "object" && tool !== null && !Array.isArray(tool) && typeof tool.name === "string" ? [tool.name] : [])
+}
diff --git a/plugins/lfg/bin/lfg-mcp.ts b/plugins/lfg/bin/lfg-mcp.ts
index b9ff9df..b33ba7e 100644
--- a/plugins/lfg/bin/lfg-mcp.ts
+++ b/plugins/lfg/bin/lfg-mcp.ts
@@ -1,7 +1,159 @@
 #!/usr/bin/env bun
-import { runStdioServer } from "../src/mcp-ts/server"
+import { createInterface } from "node:readline"
+import { join, resolve } from "node:path"
 
-runStdioServer().catch((error) => {
-  process.stderr.write(`lfg-mcp: ${error instanceof Error ? error.message : String(error)}\n`)
-  process.exit(1)
-})
+type JsonPrimitive = null | boolean | number | string
+type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue }
+type JsonRecord = { [key: string]: JsonValue }
+type JsonRpcId = string | number | null
+type JsonRpcResponse = { readonly jsonrpc: "2.0"; readonly id: JsonRpcId; readonly result?: JsonValue; readonly error?: { readonly code: number; readonly message: string; readonly data?: JsonValue } }
+type JsonRpcRequest = { readonly id?: JsonRpcId; readonly method?: string; readonly params?: unknown }
+type McpTool = { readonly name: string; readonly description: string; readonly inputSchema: JsonRecord }
+
+const PLUGIN_ROOT = resolve(import.meta.dir, "..")
+const TOOLS: readonly McpTool[] = [
+  { name: "status", description: "Show the local lfg lazycodex adapter installer status.", inputSchema: emptySchema() },
+  { name: "doctor", description: "Check the minimal lfg lazycodex adapter installer.", inputSchema: emptySchema() },
+  { name: "lazycodex", description: "Return the lazycodex-ai install plan or status.", inputSchema: actionSchema(["install", "status"]) },
+  { name: "setup", description: "Return the non-mutating lazycodex-ai setup install plan.", inputSchema: actionSchema(["install-plan", "show"]) },
+]
+
+await runStdioServer()
+
+async function runStdioServer(): Promise<void> {
+  const reader = createInterface({ input: process.stdin, crlfDelay: Infinity })
+  for await (const line of reader) {
+    const trimmed = line.trim()
+    if (!trimmed) continue
+    writeResponse(await handleLine(trimmed))
+  }
+}
+
+async function handleLine(line: string): Promise<JsonRpcResponse> {
+  try {
+    return await handleMessage(JSON.parse(line) as unknown)
+  } catch (error) {
+    if (error instanceof SyntaxError) return jsonRpcError(null, -32700, "Parse error")
+    return jsonRpcError(null, -32603, error instanceof Error ? error.message : String(error))
+  }
+}
+
+async function handleMessage(message: unknown): Promise<JsonRpcResponse> {
+  const request = normalizeRequest(message)
+  if (!request) return jsonRpcError(null, -32600, "Invalid Request")
+  const id = request.id ?? null
+  if (!request.method) return jsonRpcError(id, -32600, "Invalid Request")
+  if (request.method === "initialize") return jsonRpcResult(id, { protocolVersion: "2024-11-05", capabilities: { tools: {} }, serverInfo: { name: "lfg-harness", version: await pluginVersion() } })
+  if (request.method === "notifications/initialized") return jsonRpcResult(id, {})
+  if (request.method === "tools/list") return jsonRpcResult(id, { tools: [...TOOLS] })
+  if (request.method === "tools/call") return jsonRpcResult(id, await callTool(asJsonRecord(request.params)))
+  if (request.method === "ping") return jsonRpcResult(id, {})
+  return jsonRpcError(id, -32601, `Method not found: ${request.method}`)
+}
+
+async function callTool(params: JsonRecord): Promise<JsonRecord> {
+  const name = typeof params.name === "string" ? params.name : ""
+  const args = asJsonRecord(params.arguments)
+  if (name === "status") return textResult(await runLfgJson(["status"]))
+  if (name === "doctor") return textResult(await runLfgJson(["doctor"]))
+  if (name === "lazycodex") {
+    const action = typeof args.action === "string" ? args.action : "status"
+    if (action === "install") return textResult(await runLfgJson(["lazycodex", "install"]))
+    if (action === "status") return textResult(await runLfgJson(["lazycodex", "status"]))
+  }
+  if (name === "setup") {
+    const action = typeof args.action === "string" ? args.action : "install-plan"
+    if (action === "install-plan") return textResult(await runLfgJson(["setup", "install-plan"]))
+    if (action === "show") return textResult(await runLfgJson(["setup", "show"]))
+  }
+  throw new Error(name)
+}
+
+async function runLfgJson(args: readonly string[]): Promise<JsonRecord> {
+  const cmd = [join(PLUGIN_ROOT, "bin", "lfg"), "--json", ...args]
+  const proc = Bun.spawn(cmd, { stdout: "pipe", stderr: "pipe", env: process.env })
+  const [returncode, stdout, stderr] = await Promise.all([proc.exited, new Response(proc.stdout).text(), new Response(proc.stderr).text()])
+  const stdoutText = stdout.trim()
+  let data: JsonValue = null
+  let parseError: string | null = null
+  if (stdoutText) {
+    try {
+      data = toJsonValue(JSON.parse(stdoutText))
+    } catch (error) {
+      parseError = error instanceof Error ? error.message : String(error)
+    }
+  }
+  const ok = returncode === 0 && parseError === null
+  return { ok, status: ok ? "ok" : "error", cmd, returncode, data, stdout, stderr, stdoutJson: parseError === null, parseError }
+}
+
+async function pluginVersion(): Promise<string> {
+  try {
+    const parsed: unknown = JSON.parse(await Bun.file(join(PLUGIN_ROOT, "package.json")).text())
+    if (isRecord(parsed) && typeof parsed.version === "string") return parsed.version
+  } catch {}
+  return "0.0.0"
+}
+
+function normalizeRequest(message: unknown): JsonRpcRequest | null {
+  if (!isRecord(message)) return null
+  const id = normalizeId(message.id)
+  if (message.id !== undefined && id === undefined) return null
+  return { id, method: typeof message.method === "string" ? message.method : undefined, params: message.params }
+}
+
+function normalizeId(value: unknown): JsonRpcId | undefined {
+  if (value === undefined) return undefined
+  if (value === null || typeof value === "string") return value
+  if (typeof value === "number" && Number.isFinite(value)) return value
+  return undefined
+}
+
+function textResult(value: unknown): JsonRecord {
+  return { content: [{ type: "text", text: JSON.stringify(toJsonValue(value), null, 2) }] }
+}
+
+function jsonRpcResult(id: JsonRpcId, result: JsonValue = {}): JsonRpcResponse {
+  return { jsonrpc: "2.0", id, result }
+}
+
+function jsonRpcError(id: JsonRpcId, code: number, message: string, data?: JsonValue): JsonRpcResponse {
+  return { jsonrpc: "2.0", id, error: data === undefined ? { code, message } : { code, message, data } }
+}
+
+function writeResponse(response: JsonRpcResponse): void {
+  process.stdout.write(`${JSON.stringify(response)}\n`)
+}
+
+function emptySchema(): JsonRecord {
+  return { type: "object", additionalProperties: false, properties: {} }
+}
+
+function actionSchema(actions: readonly string[]): JsonRecord {
+  return { type: "object", additionalProperties: false, properties: { action: { type: "string", enum: [...actions] } } }
+}
+
+function asJsonRecord(value: unknown): JsonRecord {
+  return isJsonRecord(value) ? value : {}
+}
+
+function toJsonValue(value: unknown): JsonValue {
+  return isJsonValue(value) ? value : String(value)
+}
+
+function isJsonRecord(value: unknown): value is JsonRecord {
+  if (!isRecord(value)) return false
+  return Object.values(value).every(isJsonValue)
+}
+
+function isJsonValue(value: unknown): value is JsonValue {
+  if (value === null) return true
+  if (typeof value === "string" || typeof value === "boolean") return true
+  if (typeof value === "number") return Number.isFinite(value)
+  if (Array.isArray(value)) return value.every(isJsonValue)
+  return isJsonRecord(value)
+}
+
+function isRecord(value: unknown): value is Record<string, unknown> {
+  return typeof value === "object" && value !== null && !Array.isArray(value)
+}
diff --git a/plugins/lfg/bin/lfg.test.ts b/plugins/lfg/bin/lfg.test.ts
new file mode 100644
index 0000000..295c8c6
--- /dev/null
+++ b/plugins/lfg/bin/lfg.test.ts
@@ -0,0 +1,110 @@
+import { describe, expect, test } from "bun:test"
+import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises"
+import { tmpdir } from "node:os"
+import { join } from "node:path"
+
+const LFG = new URL("lfg", import.meta.url).pathname
+
+describe("lfg CLI", () => {
+  test("package metadata does not identify lfg as a plugin", async () => {
+    const parsed = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8")) as Record<string, unknown>
+    expect(parsed.name).toBe("@lfg/lazycodex-adapter-installer")
+    expect(parsed.description).toBe("Installs the lazycodex Codex adapter for grok-build.")
+    expect(JSON.stringify(parsed)).not.toContain("@lfg/plugin")
+    expect(JSON.stringify(parsed)).not.toContain("plugin postinstall")
+  })
+
+  test("reports lazycodex adapter install command and target", async () => {
+    const result = await runLfg(["--json", "lazycodex", "install"])
+    expect(result.exitCode).toBe(0)
+    expect(result.json).toMatchObject({
+      ok: true,
+      role: "lazycodex_adapter_installer",
+      adapterPackage: "lazycodex-ai",
+      installerCommand: "npx lazycodex-ai install",
+      grokBuildUse: true,
+      adapterRoot: expect.stringContaining(join(".grok", "installed-plugins", "0-1-0-ff47fdd7")),
+      adapterManifest: expect.stringContaining(join(".codex-plugin", "plugin.json")),
+    })
+    expect(JSON.stringify(result.json)).not.toContain("Grok plugin")
+    expect(JSON.stringify(result.json)).not.toContain("grok_plugin")
+  })
+
+  test("status and setup describe lfg as adapter installer not plugin", async () => {
+    const status = await runLfg(["--json", "status"])
+    expect(status.exitCode).toBe(0)
+    expect(status.json).toMatchObject({ ok: true, purpose: "Install lazycodex Codex adapter for grok-build", lfgIsPlugin: false })
+    expect(JSON.stringify(status.json)).not.toContain("Grok plugin")
+    expect(JSON.stringify(status.json)).not.toContain("grok_plugin")
+
+    const setup = await runLfg(["--json", "setup", "install-plan"])
+    expect(setup.exitCode).toBe(0)
+    expect(setup.json).toMatchObject({ lazycodex: { adapterPackage: "lazycodex-ai", installerCommand: "npx lazycodex-ai install", lfgIsPlugin: false } })
+    expect(JSON.stringify(setup.json)).not.toContain("Grok plugin")
+    expect(JSON.stringify(setup.json)).not.toContain("grok_plugin")
+  })
+
+  test("doctor requires npx but does not present bun as installer prerequisite", async () => {
+    const result = await runLfg(["--json", "doctor"])
+    expect(result.exitCode).toBe(0)
+    expect(JSON.stringify(result.json)).toContain("exe:npx")
+    expect(JSON.stringify(result.json)).not.toContain("exe:bun")
+  })
+
+  test("unsupported ulw command explains lfg scope", async () => {
+    const result = await runLfg(["--json", "ulw"])
+    expect(result.exitCode).toBe(1)
+    expect(result.json).toMatchObject({
+      ok: false,
+      status: "error",
+      code: "unsupported_command",
+      command: "ulw",
+      role: "lazycodex_adapter_installer",
+      installerCommand: "npx lazycodex-ai install",
+      lfgIsPlugin: false,
+    })
+    expect(JSON.stringify(result.json)).toContain("does not run ulw")
+  })
+
+  test("unknown command lists supported command names", async () => {
+    const result = await runLfg(["--json", "wat"])
+    expect(result.exitCode).toBe(1)
+    expect(result.json).toMatchObject({
+      ok: false,
+      code: "unsupported_command",
+      command: "wat",
+      supportedCommands: ["status", "doctor", "lazycodex install", "lazycodex status", "setup install-plan", "setup show"],
+    })
+  })
+
+  test("uses configured lazycodex adapter root", async () => {
+    const adapterRoot = await makeAdapterRoot()
+    const result = await runLfg(["--json", "lazycodex", "status"], { LAZYCODEX_ADAPTER_ROOT: adapterRoot })
+
+    expect(result.exitCode).toBe(0)
+    expect(result.json).toMatchObject({
+      adapter: {
+        found: true,
+        root: adapterRoot,
+        manifest: join(adapterRoot, ".codex-plugin", "plugin.json"),
+        mcpConfig: join(adapterRoot, ".mcp.json"),
+        skillsDir: join(adapterRoot, "skills"),
+      },
+    })
+  })
+})
+
+async function runLfg(args: readonly string[], env: Readonly<Record<string, string>> = {}): Promise<{ readonly exitCode: number; readonly json: unknown }> {
+  const proc = Bun.spawn([LFG, ...args], { stdout: "pipe", stderr: "pipe", env: { ...process.env, ...env } })
+  const [stdout, exitCode] = await Promise.all([new Response(proc.stdout).text(), proc.exited])
+  return { exitCode, json: JSON.parse(stdout) as unknown }
+}
+
+async function makeAdapterRoot(): Promise<string> {
+  const root = await mkdtemp(join(tmpdir(), "lfg-lazycodex-adapter."))
+  await mkdir(join(root, ".codex-plugin"), { recursive: true })
+  await mkdir(join(root, "skills"), { recursive: true })
+  await writeFile(join(root, ".codex-plugin", "plugin.json"), `${JSON.stringify({ name: "lazycodex", version: "0.1.0" })}\n`)
+  await writeFile(join(root, ".mcp.json"), `${JSON.stringify({ mcpServers: {} })}\n`)
+  return root
+}
diff --git a/plugins/lfg/bin/lfg.ts b/plugins/lfg/bin/lfg.ts
index db0e924..d2512a7 100644
--- a/plugins/lfg/bin/lfg.ts
+++ b/plugins/lfg/bin/lfg.ts
@@ -1,131 +1,261 @@
 #!/usr/bin/env bun
-import { agentsInspect, agentsList } from "../src/runtime-ts/commands/agents"
-import { authLogin } from "../src/runtime-ts/commands/auth"
-import { doctor, doctorStateSchemaCheck } from "../src/runtime-ts/commands/doctor"
-import { modelsShow } from "../src/runtime-ts/commands/models"
-import { providerAdd, providerList, providerShow } from "../src/runtime-ts/commands/provider"
-import { setup, setupCheck, setupInstallPlan, setupShow } from "../src/runtime-ts/commands/setup"
-import { status } from "../src/runtime-ts/commands/status"
-import { asString, type JsonObject } from "../src/runtime-ts/commands/common"
-
-type ParsedArgs = { json: boolean; positional: string[]; flags: Record<string, string | boolean> }
-
-async function main(argv: string[]): Promise<number> {
+import { existsSync } from "node:fs"
+import { access, stat } from "node:fs/promises"
+import { homedir } from "node:os"
+import { join, resolve } from "node:path"
+import { commandPath, SUPPORTED_COMMANDS, unsupportedCommand } from "./lfg-command"
+import { isRecord, readJson, readJsonObject, type JsonObject } from "./lfg-json"
+
+type LfgEnv = { readonly root: string; readonly data: string; readonly stateDir: string; readonly launcher: string }
+type ParsedArgs = { readonly json: boolean; readonly positional: readonly string[] }
+type LazycodexAdapter = {
+  readonly found: boolean
+  readonly root: string
+  readonly manifest: string
+  readonly mcpConfig: string
+  readonly skillsDir: string
+}
+
+const STATE_SCHEMA_VERSION = 2
+
+async function main(argv: readonly string[]): Promise<number> {
   const parsed = parseArgs(argv)
   try {
-    const result = await dispatch(parsed, argv)
+    const result = await dispatch(parsed)
     emit(result, parsed.json)
     return isFailure(result) ? 1 : 0
   } catch (error) {
-    const message = error instanceof Error ? error.message : String(error)
-    if (parsed.json) emit({ ok: false, status: "error", error: message }, true)
-    else console.error(message)
+    emit({ ok: false, status: "error", error: error instanceof Error ? error.message : String(error) }, true)
     return 1
   }
 }
 
-async function dispatch(args: ParsedArgs, rawArgv: string[]): Promise<unknown> {
-  const [command, subcommand, third] = args.positional
-  const rawAfterCommand = (cmd: string) => { const idx = rawArgv.indexOf(cmd); return idx >= 0 ? rawArgv.slice(idx + 1) : args.positional.slice(1) }
-  if (!command || command === "status") return status({ argv0: Bun.argv[1] })
+async function dispatch(args: ParsedArgs): Promise<unknown> {
+  const [command, subcommand, third, fourth] = args.positional
+  if (!command || command === "status") return status()
   if (command === "doctor") {
-    if (subcommand === "state" && third === "schema" && args.positional[3] === "check") return doctorStateSchemaCheck()
+    if (subcommand === "state" && third === "schema" && fourth === "check") return doctorStateSchemaCheck()
     return doctor()
   }
-  if (command === "agents") {
-    if (subcommand === "list") return agentsList({ ids: Boolean(args.flags.ids ?? args.flags.completion), json: args.json })
-    if (subcommand === "inspect") return agentsInspect({ agentId: required(args.positional[2], "agents inspect requires <id>"), category: flagString(args, "category"), provider: flagString(args, "provider"), model: flagString(args, "model"), reasoning: flagString(args, "reasoning") })
-  }
-  if (command === "models") return modelsShow({ provider: flagString(args, "provider") })
-  if (command === "auth" && subcommand === "login") return authLogin({ provider: required(args.positional[2], "auth login requires <provider>"), id: flagString(args, "id"), env: flagString(args, "env"), model: flagString(args, "model") })
-  if (command === "provider") {
-    if (subcommand === "list") return providerList()
-    if (subcommand === "show") return providerShow({ id: required(args.positional[2], "provider show requires <id>") })
-    if (subcommand === "add") return providerAdd({ id: required(flagString(args, "id"), "provider add requires --id"), kind: required(flagString(args, "kind"), "provider add requires --kind"), env: flagString(args, "env"), model: flagString(args, "model"), transport: flagString(args, "transport"), authScheme: flagString(args, "auth-scheme") ?? flagString(args, "authScheme"), baseUrl: flagString(args, "base-url") ?? flagString(args, "baseUrl") })
+  if (command === "lazycodex") {
+    if (!subcommand || subcommand === "status") return lazycodexStatus()
+    if (subcommand === "install") return lazycodexInstallPlan()
   }
   if (command === "setup") {
-    if (subcommand === "check") return setupCheck()
-    if (subcommand === "install-plan") return setupInstallPlan({ marketplace: flagString(args, "marketplace") })
+    if (!subcommand || subcommand === "install-plan") return setupInstallPlan()
     if (subcommand === "show") return setupShow()
-    return setup({ pluginDir: flagString(args, "plugin-dir"), dryRun: Boolean(args.flags["dry-run"]) })
   }
-  if (command === "team") return (await import("../src/runtime-ts/commands/team")).teamCommand(rawAfterCommand("team"))
-  if (command === "ultrawork") return (await import("../src/runtime-ts/commands/ultrawork")).ultraworkCommand(rawAfterCommand("ultrawork"))
-  if (command === "slash") return (await import("../src/runtime-ts/commands/slash")).slashCommand(rawAfterCommand("slash"))
-  if (command === "goal") return (await import("../src/runtime-ts/commands/goal")).goalCommand(rawAfterCommand("goal"))
-  if (command === "route") return (await import("../src/runtime-ts/commands/route")).routeCommand(rawAfterCommand("route"))
-  if (command === "spawn") return (await import("../src/runtime-ts/commands/spawn")).spawnCommand(rawAfterCommand("spawn"))
-  if (command === "plan") {
-    const planMod = await import("../src/runtime-ts/commands/plan")
-    const planArgs = rawAfterCommand("plan")
-    if (subcommand === "create") return planMod.planCreateCommand({ objective: args.positional.slice(2).join(" ") || "unnamed plan", steps: flagString(args, "steps")?.split(";").map((s) => s.trim()).filter(Boolean) ?? [] })
-    if (subcommand === "list") return planMod.planListCommand({ limit: Number(flagString(args, "limit") ?? "10") })
-    return planMod.planListCommand({})
+  if (command === "help" || command === "--help" || command === "-h") return help()
+  return unsupportedCommand(args.positional)
+}
+
+async function status(): Promise<JsonObject> {
+  const env = resolveLfgEnv()
+  return {
+    ok: true,
+    product: "lfg",
+    purpose: "Install lazycodex Codex adapter for grok-build",
+    role: "lazycodex_adapter_installer",
+    lfgIsPlugin: false,
+    version: await readPluginVersion(env),
+    launcher: env.launcher,
+    helperRoot: env.root,
+    helperData: env.data,
+    repo: await detectRepo(),
+    lazycodex: lazycodexInstallPlan(),
   }
-  if (command === "atlas") {
-    const atlasMod = await import("../src/runtime-ts/commands/atlas")
-    const planId = flagString(args, "plan-id") ?? flagString(args, "planId")
-    if (subcommand === "start-work") return atlasMod.atlasStartWorkCommand({ planId, plan_id: planId })
-    if (subcommand === "status") return atlasMod.atlasStatusCommand({ planId, plan_id: planId })
-    if (subcommand === "checkbox") return atlasMod.atlasCheckboxCommand({ planId, plan_id: planId, task: Number(args.positional[2] ?? 0), status: args.positional[3] ?? "complete", evidence: flagString(args, "evidence") })
-    return atlasMod.atlasStatusCommand({ planId, plan_id: planId })
+}
+
+async function doctor(): Promise<JsonObject> {
+  const env = resolveLfgEnv()
+  const schema = await inspectStateSchema(env)
+  const checks: JsonObject[] = []
+  const add = (name: string, ok: boolean, evidence: string, required = true): void => {
+    checks.push({ name, ok, required, evidence })
   }
-  if (command === "boulder") {
-    const boulderMod = await import("../src/runtime-ts/commands/boulder")
-    if (subcommand === "status") return boulderMod.boulderStatusCommand()
-    if (subcommand === "set-goal") return boulderMod.boulderSetGoalCommand({ goal: args.positional.slice(2).join(" ") || "unnamed goal" })
-    if (subcommand === "add-evidence") return boulderMod.boulderAddEvidenceCommand({ evidence: args.positional.slice(2).join(" ") || "checkpoint", taskId: flagString(args, "task-id") })
-    if (subcommand === "add-blocker") return boulderMod.boulderAddBlockerCommand({ blocker: args.positional.slice(2).join(" ") || "unspecified blocker", code: flagString(args, "code") })
-    return boulderMod.boulderStatusCommand()
+
+  const adapter = detectLazycodexAdapter()
+  add("adapter_manifest", adapter.found, adapter.manifest, false)
+  add("adapter_mcp_config", await pathExists(adapter.mcpConfig), adapter.mcpConfig, false)
+  add("adapter_skills", await directoryExists(adapter.skillsDir), adapter.skillsDir, false)
+  for (const [exe, required] of [["npx", true], ["grok", false]] as const) {
+    const found = commandPath(exe)
+    add(`exe:${exe}`, Boolean(found), found ?? "not found", required)
   }
-  if (command === "hyperplan") return (await import("../src/runtime-ts/commands/hyperplan")).hyperplanCommand(rawAfterCommand("hyperplan"))
-  const workflowStubs = await import("../src/runtime-ts/commands/workflow-stubs")
-  if (workflowStubs.isWorkflowStubCommand(command)) return workflowStubs.workflowStubCommand(command, args.positional.slice(1))
-  throw new Error(`unknown command: ${args.positional.join(" ")}`)
-}
-
-function parseArgs(argv: string[]): ParsedArgs {
-  const flags: Record<string, string | boolean> = {}
-  const positional: string[] = []
-  let json = false
-  for (let index = 0; index < argv.length; index += 1) {
-    const token = argv[index]
-    if (token === "--json") { json = true; continue }
-    if (token.startsWith("--")) {
-      const withoutPrefix = token.slice(2)
-      const [key, inlineValue] = withoutPrefix.split("=", 2)
-      if (inlineValue !== undefined) flags[key] = inlineValue
-      else if (argv[index + 1] && !argv[index + 1].startsWith("--")) { flags[key] = argv[index + 1]; index += 1 }
-      else flags[key] = true
-      continue
-    }
-    positional.push(token)
+  add("helper_data", await directoryExists(env.data) || await directoryExists(resolve(env.data, "..")), env.data)
+  add("state_schema", schema.version === STATE_SCHEMA_VERSION, `virtual schema version=${schema.version}; no local write`)
+  add("cli", await pathExists(join(env.root, "bin", "lfg.ts")), join(env.root, "bin", "lfg.ts"))
+
+  const failedRequired = checks.filter((check) => check.required === true && check.ok !== true)
+  const warnings = checks.filter((check) => check.required !== true && check.ok !== true)
+  return { ok: failedRequired.length === 0, status: failedRequired.length === 0 ? "pass" : "fail", helperRoot: env.root, helperData: env.data, lfgIsPlugin: false, adapter, installer: lazycodexInstallPlan(), checks, failedRequired, warnings }
+}
+
+async function doctorStateSchemaCheck(): Promise<JsonObject> {
+  const env = resolveLfgEnv()
+  const schema = await inspectStateSchema(env)
+  return { ok: true, status: "pass", operation: "doctor_state_schema_check", schema, stateRoots: { state: env.stateDir }, migrationStatus: schema.migrationStatus, migrations: schema.migrations }
+}
+
+function lazycodexStatus(): JsonObject {
+  return {
+    ok: true,
+    status: "ready",
+    command: "lazycodex status",
+    role: "lazycodex_adapter_installer",
+    adapterPackage: "lazycodex-ai",
+    purpose: "Install lazycodex Codex adapter for grok-build",
+    primaryAction: "npx lazycodex-ai install",
+    grokBuildUse: true,
+    lfgIsPlugin: false,
+    adapter: detectLazycodexAdapter(),
+    install: lazycodexInstallPlan(),
+  }
+}
+
+function lazycodexInstallPlan(): JsonObject {
+  const adapter = detectLazycodexAdapter()
+  return {
+    ok: true,
+    status: "planned",
+    command: "lazycodex install",
+    role: "lazycodex_adapter_installer",
+    adapterPackage: "lazycodex-ai",
+    installerCommand: "npx lazycodex-ai install",
+    mutatesGlobalConfig: false,
+    grokBuildUse: true,
+    lfgIsPlugin: false,
+    adapterRoot: adapter.root,
+    adapterManifest: adapter.manifest,
+    adapter,
+    steps: [
+      { id: "run_npm_installer", status: "pending", text: "Run npx lazycodex-ai install." },
+      { id: "use_lazycodex_adapter", status: "pending", text: `Use lazycodex adapter from ${adapter.root} when running grok-build.` },
+      { id: "verify_lazycodex_adapter", status: "pending", text: "Confirm the lazycodex adapter exposes .codex-plugin/plugin.json, .mcp.json, and skills/." },
+    ],
+  }
+}
+
+async function setupInstallPlan(): Promise<JsonObject> {
+  const env = resolveLfgEnv()
+  const install = lazycodexInstallPlan()
+  const installSteps = Array.isArray(install.steps) ? install.steps : []
+  const record = {
+    status: "planned",
+    updatedAt: utcNow(),
+    purpose: "Install lazycodex Codex adapter for grok-build",
+    steps: installSteps.map((step, index) => ({ id: index + 1, key: isRecord(step) ? step.id : undefined, status: isRecord(step) ? step.status : undefined, text: isRecord(step) ? step.text : undefined })),
+    lazycodex: { adapterPackage: install.adapterPackage, mutatesGlobalConfig: false, installerCommand: install.installerCommand, lfgIsPlugin: false, adapterRoot: install.adapterRoot },
   }
-  return { json, positional, flags }
+  return record
+}
+
+async function setupShow(): Promise<unknown> {
+  return readJson(setupPath(resolveLfgEnv()), { setup: [] })
 }
 
-function flagString(args: ParsedArgs, name: string): string | undefined {
-  return asString(args.flags[name])
+async function inspectStateSchema(env: LfgEnv): Promise<JsonObject> {
+  const path = stateSchemaPath(env)
+  const current = await readJsonObject(path)
+  const previous = typeof current.version === "number" ? current.version : null
+  const now = utcNow()
+  const schema = {
+    name: "lfg-state",
+    version: STATE_SCHEMA_VERSION,
+    createdAt: typeof current.createdAt === "string" ? current.createdAt : now,
+    updatedAt: now,
+    stateDir: env.stateDir,
+    runsDir: join(env.data, "runs"),
+    migrations: previous === STATE_SCHEMA_VERSION ? [] : [{ id: `state-schema-v${previous ?? 0}-to-${STATE_SCHEMA_VERSION}`, ts: now, from: previous, to: STATE_SCHEMA_VERSION, status: "pending" }],
+    migrationStatus: previous === STATE_SCHEMA_VERSION ? "current" : "not_written",
+    roots: ["state"],
+  }
+  return schema
 }
 
-function required(value: string | undefined, message: string): string {
-  if (!value) throw new Error(message)
-  return value
+function resolveLfgEnv(): LfgEnv {
+  const cwd = process.cwd()
+  const root = resolve(process.env.GROK_PLUGIN_ROOT ?? resolve(cwd, "plugins", "lfg"))
+  const data = resolve(process.env.GROK_PLUGIN_DATA ?? join(cwd, ".lfg"))
+  return { root, data, stateDir: join(data, "state"), launcher: process.env.LFG_LAUNCHER ?? "lfg" }
+}
+
+function parseArgs(argv: readonly string[]): ParsedArgs {
+  const positional = argv.filter((arg) => arg !== "--json")
+  return { json: argv.includes("--json"), positional }
 }
 
 function emit(value: unknown, json: boolean): void {
-  if (!json && isRecord(value) && typeof value._raw_text === "string") console.log(value._raw_text)
-  else console.log(JSON.stringify(value, null, 2))
+  if (json || typeof value !== "string") {
+    process.stdout.write(`${JSON.stringify(value, null, 2)}\n`)
+    return
+  }
+  process.stdout.write(`${value}\n`)
 }
 
 function isFailure(value: unknown): boolean {
   return isRecord(value) && value.ok === false
 }
 
-function isRecord(value: unknown): value is JsonObject {
-  return typeof value === "object" && value !== null && !Array.isArray(value)
+function help(): string {
+  return ["lfg - lazycodex Codex adapter installer", "", "Commands:", ...SUPPORTED_COMMANDS.map((command) => `  lfg ${command}`)].join("\n")
+}
+
+function detectLazycodexAdapter(): LazycodexAdapter {
+  const root = lazycodexAdapterRoot()
+  const manifest = join(root, ".codex-plugin", "plugin.json")
+  const mcpConfig = join(root, ".mcp.json")
+  const skillsDir = join(root, "skills")
+  return {
+    found: existsSync(manifest),
+    root,
+    manifest,
+    mcpConfig,
+    skillsDir,
+  }
+}
+
+function lazycodexAdapterRoot(): string {
+  return resolve(process.env.LAZYCODEX_ADAPTER_ROOT ?? join(homedir(), ".grok", "installed-plugins", "0-1-0-ff47fdd7"))
+}
+
+async function readPluginVersion(env: LfgEnv): Promise<string | null> {
+  const manifest = await readJsonObject(join(env.root, "package.json"))
+  return typeof manifest.version === "string" ? manifest.version : null
+}
+
+async function detectRepo(): Promise<JsonObject> {
+  const root = process.cwd()
+  return { root, isGit: await directoryExists(join(root, ".git")) }
+}
+
+async function pathExists(path: string): Promise<boolean> {
+  try {
+    await access(path)
+    return true
+  } catch {
+    return false
+  }
+}
+
+async function directoryExists(path: string): Promise<boolean> {
+  try {
+    return (await stat(path)).isDirectory()
+  } catch {
+    return false
+  }
+}
+
+function setupPath(env: LfgEnv): string {
+  return join(env.stateDir, "setup.json")
 }
 
-if (import.meta.main) process.exit(await main(Bun.argv.slice(2)))
+function stateSchemaPath(env: LfgEnv): string {
+  return join(env.stateDir, "schema.json")
+}
+
+function utcNow(): string {
+  return new Date().toISOString().replace(/\.\d{3}Z$/, "Z")
+}
 
-export { dispatch, parseArgs }
+process.exit(await main(Bun.argv.slice(2)))
diff --git a/plugins/lfg/bin/self-test.ts b/plugins/lfg/bin/self-test.ts
old mode 100755
new mode 100644
index 429f270..32271b6
--- a/plugins/lfg/bin/self-test.ts
+++ b/plugins/lfg/bin/self-test.ts
@@ -1,5 +1,18 @@
 #!/usr/bin/env bun
-import { runSelfTest } from "../src/smoke-ts/runner"
+const checks = [
+  await commandOk(["lazycodex", "install"], "npx lazycodex-ai install"),
+  await commandOk(["lazycodex", "status"], "npx lazycodex-ai install"),
+  await commandOk(["doctor"], "\"ok\": true"),
+]
 
-const result = await runSelfTest()
-process.exit(result.ok ? 0 : 1)
+for (const [index, ok] of checks.entries()) {
+  process.stdout.write(`check-${index + 1}=${ok ? "ok" : "fail"}\n`)
+}
+
+process.exit(checks.every(Boolean) ? 0 : 1)
+
+async function commandOk(args: readonly string[], expected: string): Promise<boolean> {
+  const proc = Bun.spawn([new URL("lfg", import.meta.url).pathname, "--json", ...args], { stdout: "pipe", stderr: "pipe" })
+  const [stdout, code] = await Promise.all([new Response(proc.stdout).text(), proc.exited])
+  return code === 0 && stdout.includes(expected)
+}
diff --git a/plugins/lfg/bin/ulw b/plugins/lfg/bin/ulw
deleted file mode 100755
index a5362f0..0000000
--- a/plugins/lfg/bin/ulw
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-# ulw — specialized launcher for ultrawork / ultragoal-driven swarms (LFG team workers)
-# Sets LFG_LAUNCHER=ulw so the runtime and spawned sub-agents identify as the ulw swarm mode.
-
-SOURCE="$0"
-while [[ -L "$SOURCE" ]]; do
-  DIR="$(CDPATH= cd -- "$(dirname -- "$SOURCE")" && pwd)"
-  SOURCE="$(readlink "$SOURCE")"
-  [[ "$SOURCE" = /* ]] || SOURCE="$DIR/$SOURCE"
-done
-SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$SOURCE")" && pwd)"
-
-if [[ -z "${GROK_PLUGIN_ROOT:-}" ]]; then
-  CANDIDATE="$(CDPATH= cd -- "$SCRIPT_DIR/../.." && pwd)"
-  if [[ -f "$CANDIDATE/plugins/lfg/.grok-plugin/plugin.json" ]]; then
-    export GROK_PLUGIN_ROOT="$CANDIDATE"
-  else
-    export GROK_PLUGIN_ROOT="$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)"
-  fi
-fi
-
-export GROK_PLUGIN_DATA="${GROK_PLUGIN_DATA:-$PWD/.lfg}"
-export LFG_LAUNCHER="ulw"
-
-exec bun "$SCRIPT_DIR/lfg.ts" "$@"
diff --git a/plugins/lfg/package.json b/plugins/lfg/package.json
index f61add1..01c4be0 100644
--- a/plugins/lfg/package.json
+++ b/plugins/lfg/package.json
@@ -1,66 +1,28 @@
 {
-  "name": "@lfg/plugin",
+  "name": "@lfg/lazycodex-adapter-installer",
   "version": "0.1.0",
   "private": true,
   "type": "module",
-  "description": "LFG Grok plugin TypeScript runtime workspace.",
+  "description": "Installs the lazycodex Codex adapter for grok-build.",
   "bin": {
     "lfg": "./bin/lfg",
     "lfg-mcp": "./bin/lfg-mcp.ts"
   },
   "exports": {
-    ".": {
-      "types": "./src/runtime-ts/index.ts",
-      "import": "./dist/index.js"
-    },
-    "./runtime": {
-      "types": "./src/runtime-ts/index.ts",
-      "import": "./dist/index.js"
-    },
     "./cli": "./bin/lfg",
     "./mcp": "./bin/lfg-mcp.ts",
     "./package.json": "./package.json"
   },
-  "main": "./dist/index.js",
-  "module": "./dist/index.js",
-  "types": "./src/runtime-ts/index.ts",
   "files": [
-    "agents",
     "bin",
-    "config",
-    "dist",
-    "hooks",
-    "skills",
-    "src/runtime-ts",
-    ".claude-plugin",
-    ".grok-plugin",
-    ".mcp.json"
+    "skills"
   ],
   "scripts": {
-    "build": "bun build ./src/runtime-ts/index.ts --outdir ./dist --target bun --format esm --sourcemap=external",
-    "postinstall": "bun -e \"console.log('LFG plugin postinstall: no-op; run bun ./scripts/link-omo-node-modules.mjs && bun ./scripts/rebuild-vendor-links.ts after initializing plugins/lfg/vendor/omo-standalone if you need to refresh vendor-links')\"",
-    "refresh:vendor-links": "bun ./scripts/link-omo-node-modules.mjs && bun ./scripts/rebuild-vendor-links.ts",
-    "test": "bun test ./src/runtime-ts/ ./src/mcp-ts/",
+    "build": "bun build ./bin/lfg.ts ./bin/lfg-mcp.ts --outdir ./dist --target bun --format esm --sourcemap=external",
+    "postinstall": "node -e \"console.log('LFG lazycodex adapter installer postinstall: no-op')\"",
+    "test": "bun test ./bin/",
     "typecheck": "tsc --noEmit -p tsconfig.json"
   },
-  "dependencies": {
-    "@oh-my-opencode/adapter-codex": "workspace:*",
-    "@oh-my-opencode/adapter-opencode": "workspace:*",
-    "@oh-my-opencode/agents-md-core": "workspace:*",
-    "@oh-my-opencode/ast-grep-core": "workspace:*",
-    "@oh-my-opencode/boulder-state": "workspace:*",
-    "@oh-my-opencode/comment-checker-core": "workspace:*",
-    "@oh-my-opencode/hooks-core": "workspace:*",
-    "@oh-my-opencode/model-core": "workspace:*",
-    "@oh-my-opencode/rules-engine": "workspace:*",
-    "@oh-my-opencode/skills-core": "workspace:*",
-    "@oh-my-opencode/standalone-runtime": "workspace:*",
-    "@oh-my-opencode/ulw-host-contract": "workspace:*",
-    "@oh-my-opencode/ulw-intent": "workspace:*",
-    "@oh-my-opencode/ulw-kernel": "workspace:*",
-    "@oh-my-opencode/ulw-loop-state": "workspace:*",
-    "@oh-my-opencode/utils": "workspace:*"
-  },
   "devDependencies": {
     "bun-types": "1.3.14",
     "typescript": "^6.0.3"
diff --git a/plugins/lfg/skills/lazycodex/SKILL.md b/plugins/lfg/skills/lazycodex/SKILL.md
new file mode 100644
index 0000000..8eee55b
--- /dev/null
+++ b/plugins/lfg/skills/lazycodex/SKILL.md
@@ -0,0 +1,26 @@
+---
+name: lazycodex
+description: Install or verify the lazycodex Codex adapter through the lazycodex-ai npm package.
+---
+
+# LazyCodex
+
+Use this skill only as a thin installer helper for the lazycodex Codex adapter:
+
+```sh
+npx lazycodex-ai install
+```
+
+The local helper commands are:
+
+```sh
+lfg lazycodex install
+lfg lazycodex status
+lfg setup install-plan
+```
+
+The default adapter root for grok-build is:
+
+```sh
+~/.grok/installed-plugins/0-1-0-ff47fdd7
+```
