Skip to main content
Glama

exec

Execute Codex CLI commands directly using plain instructions to write, run, and review code within Claude workflows, with session management support.

Instructions

Invoke Codex CLI with a plain instruction. No template, no context wrapping — just raw execution. Supports session resume.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
instructionYesInstruction for Codex CLI
sessionIdNoResume an existing session by ID
workingDirectoryNoWorking directory path

Implementation Reference

  • Main handler function codexExec that implements the 'exec' tool logic - executes Codex CLI with raw instructions, supports session resume, manages progress tracking, and returns parsed results including file changes and session info
    export async function codexExec(
      params: CodexExecParams,
      extra?: { signal?: AbortSignal }
    ): Promise<CodexWriteResult> {
      const config = await loadConfig({ workingDirectory: params.workingDirectory });
      const toolCfg = getToolConfig(config, "exec");
      const executor = await CodexExecutor.create({
        workingDirectory: params.workingDirectory,
      });
    
      try {
        const operationId = `exec-${crypto.randomUUID()}`;
        progressServer.startOperation(operationId, "write", params.instruction.slice(0, 120));
    
        if (params.sessionId) {
          await sessionManager.updateStatus(params.sessionId, "active", {
            workingDirectory: params.workingDirectory,
          });
        }
    
        let result;
        try {
          result = await executor.executeWrite(params.instruction, {
            sessionId: params.sessionId,
            workingDirectory: params.workingDirectory,
            model: toolCfg.model,
            sandbox: toolCfg.sandbox,
            timeout: toolCfg.timeout,
            onLine: (line) => {
              const event = mapCodexLineToProgressEvent(line, operationId);
              if (event) progressServer.emit(event);
            },
            signal: extra?.signal,
          });
        } finally {
          progressServer.endOperation(operationId, result?.exitCode === 0);
        }
    
        const parsed = executor.parseOutput(result.stdout);
        const sessionId = parsed.sessionId || params.sessionId;
        if (!sessionId) {
          throw {
            code: CodexErrorCode.CODEX_INVALID_OUTPUT,
            message: "Codex CLI did not return a session ID.",
            recoverable: false,
          } satisfies CodexErrorInfo;
        }
    
        const trackedStatus = result.exitCode !== 0 ? "abandoned" : "completed";
        if (params.sessionId) {
          await sessionManager.markResumed(params.sessionId, {
            workingDirectory: params.workingDirectory,
          });
          await sessionManager.updateStatus(params.sessionId, trackedStatus, {
            workingDirectory: params.workingDirectory,
          });
        } else {
          await sessionManager.track({
            sessionId,
            type: "exec",
            instruction: params.instruction,
            createdAt: new Date().toISOString(),
            status: trackedStatus,
          }, { workingDirectory: params.workingDirectory });
        }
    
        let status: CodexWriteResult["status"] = "completed";
        if (result.exitCode !== 0) {
          status = "error";
        } else if (parsed.filesCreated.length > 0 || parsed.filesModified.length > 0) {
          status = "needs_review";
        }
    
        return {
          success: result.exitCode === 0,
          sessionId,
          output: {
            summary: parsed.summary,
            filesModified: parsed.filesModified,
            filesCreated: parsed.filesCreated,
          },
          status,
        };
      } catch (error) {
        if (params.sessionId) {
          try {
            await sessionManager.updateStatus(params.sessionId, "abandoned", {
              workingDirectory: params.workingDirectory,
            });
          } catch {
            /* best effort */
          }
        }
        const errorInfo = error as CodexErrorInfo;
        return {
          success: false,
          sessionId: params.sessionId || "",
          output: { summary: "", filesModified: [], filesCreated: [] },
          status: "error",
          error: {
            code: errorInfo.code || CodexErrorCode.UNKNOWN_ERROR,
            message: errorInfo.message || String(error),
            recoverable: errorInfo.recoverable ?? false,
            suggestion: errorInfo.suggestion,
          },
        };
      }
    }
  • Zod schema definition for the 'exec' tool parameters - validates instruction (required), sessionId (optional UUID), and workingDirectory (optional)
    export const CodexExecParamsSchema = z.object({
      instruction: z.string().describe("Instruction for Codex CLI"),
      sessionId: z.string().uuid().optional().describe("Resume an existing session by ID"),
      workingDirectory: z.string().optional().describe("Working directory path"),
    });
    
    export type CodexExecParams = z.infer<typeof CodexExecParamsSchema>;
  • src/index.ts:54-72 (registration)
    MCP server registration of the 'exec' tool - defines tool name, description, input schema using zod, and maps to the codexExec handler function
    // ─── exec ──────────────────────────────────────────────────────────
    if (isToolEnabled(config, "exec")) {
      server.tool(
        "exec",
        "Invoke Codex CLI with a plain instruction. No template, no context wrapping — just raw execution. Supports session resume.",
        {
          instruction: z.string().describe("Instruction for Codex CLI"),
          sessionId: z
            .string()
            .optional()
            .describe("Resume an existing session by ID"),
          workingDirectory: z.string().optional().describe("Working directory path"),
        },
        async (params, extra) => {
          const result = await codexExec(params, extra);
          return {
            content: [
              {
                type: "text" as const,
  • executeWrite method in CodexExecutor service - handles actual Codex CLI process spawning with proper argument building for 'exec' command, including session resume support
    async executeWrite(
      instruction: string,
      options: {
        sessionId?: string;
        workingDirectory?: string;
        model?: string;
        sandbox?: SandboxMode;
        timeout?: number;
        onLine?: (line: string) => void;
        signal?: AbortSignal;
      }
    ): Promise<ExecuteResult> {
      await this.checkCodexInstalled();
    
      const { args, stdinContent } = this.buildWriteArgs(instruction, options);
      return this.spawnCodex(args, {
        cwd: options.workingDirectory,
        timeout: options.timeout ?? this.config.timeout,
        stdinContent,
        onLine: options.onLine,
        signal: options.signal,
      });
    }
  • buildWriteArgs helper method - constructs CLI arguments for the 'exec' command, handling both new sessions and session resume with proper flags for model, sandbox, and JSON output
    private buildWriteArgs(
      instruction: string,
      options: {
        sessionId?: string;
        model?: string;
        sandbox?: SandboxMode;
      }
    ): { args: string[]; stdinContent: string } {
      const args: string[] = [];
    
      // Always use stdin to avoid shell injection with shell: true
      if (options.sessionId) {
        args.push("exec", "resume", options.sessionId, "-");
      } else {
        args.push("exec", "-");
      }
    
      args.push("--json");
    
      const model = options.model || this.config.model;
      if (model) {
        args.push("--model", model);
      }
    
      // --sandbox is only valid for new sessions, not resume
      if (!options.sessionId) {
        const sandboxMode = options.sandbox || this.config.sandbox || "danger-full-access";
        args.push("--sandbox", sandboxMode);
      } else {
        // resume does not support --sandbox; bypass sandbox to allow file writes
        args.push("--dangerously-bypass-approvals-and-sandbox");
      }
    
      return { args, stdinContent: instruction };
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/FYZAFH/mcp-codex-dev'

If you have feedback or need assistance with the MCP directory API, please join our Discord server