Operational Workflows

Copy Markdown View Source

This guide covers the newly synced runtime workflows that sit between local authoring and normal thread execution:

  • marketplace acquisition
  • MCP inventory and thread-scoped MCP execution
  • thread history injection and memory controls
  • filesystem watches

Marketplace Acquisition And Maintenance

There are two runtime entry points for adding a marketplace source:

CLI passthrough:

{:ok, result} =
  Codex.CLI.marketplace_add(
    "./source-marketplace",
    cwd: "/tmp/workspace",
    env: %{"CODEX_HOME" => "/tmp/codex-home"}
  )

IO.puts(result.stdout)

App-server request:

{:ok, conn} =
  Codex.AppServer.connect(codex_opts,
    cwd: "/tmp/workspace",
    process_env: %{"CODEX_HOME" => "/tmp/codex-home"}
  )

{:ok, response} =
  Codex.AppServer.marketplace_add(
    conn,
    "./source-marketplace",
    ref_name: "main",
    sparse_paths: ["plugins/demo-plugin"]
  )

IO.inspect(response)

The app-server surface also exposes marketplace maintenance:

{:ok, _} = Codex.AppServer.marketplace_upgrade(conn, marketplace_name: "source-marketplace")
{:ok, _} = Codex.AppServer.marketplace_remove(conn, "source-marketplace")

Use isolated CODEX_HOME values for examples, tests, and migration flows so you do not mutate your real installed marketplace set unintentionally.

Thread Repair And Memory Controls

Inject raw response items

thread/inject_items appends raw Responses API items to the thread's model-visible history.

items = [
  %{
    "type" => "message",
    "role" => "assistant",
    "content" => [%{"type" => "output_text", "text" => "Recovered checkpoint"}]
  }
]

{:ok, %{}} = Codex.AppServer.thread_inject_items(conn, thread_id, items)

Use this when a host flow needs to reconstruct or repair thread-visible state after an out-of-band recovery step.

Toggle thread memory mode

thread/memoryMode/set is experimental and requires experimental_api: true when connecting.

{:ok, conn} = Codex.AppServer.connect(codex_opts, experimental_api: true)
{:ok, %{}} = Codex.AppServer.thread_memory_mode_set(conn, thread_id, :disabled)

Accepted local forms:

  • :enabled
  • :disabled
  • "enabled"
  • "disabled"

Reset memory state

memory/reset is also experimental and destructive. Use it only with an isolated CODEX_HOME unless you explicitly want to clear the active memory store for that Codex home.

{:ok, conn} = Codex.AppServer.connect(codex_opts, experimental_api: true)
{:ok, %{}} = Codex.AppServer.memory_reset(conn)

MCP Inventory And Execution

The app-server MCP helper now supports:

  • inventory detail filtering
  • resource reads
  • thread-scoped tool calls

Inventory detail

{:ok, %{"data" => servers}} =
  Codex.AppServer.Mcp.list_servers(conn, detail: :tools_and_auth_only)

Accepted detail selectors:

  • :full
  • :tools_and_auth_only

Resource reads

{:ok, %{"contents" => contents}} =
  Codex.AppServer.Mcp.resource_read(conn, thread_id, "codex_apps", "test://resource")

Tool calls

{:ok, response} =
  Codex.AppServer.Mcp.tool_call(
    conn,
    thread_id,
    "docs",
    "search",
    arguments: %{"query" => "rate limits"},
    meta: %{"source" => "sdk"}
  )

IO.inspect(response["structuredContent"])

Treat MCP tool execution as an external side-effect boundary. Do not auto-run arbitrary tools just because they are discoverable.

Filesystem Watches

The thin app-server filesystem wrapper now includes fs/watch and fs/unwatch. Notifications still arrive through the normal subscribe/2 channel as fs/changed.

:ok = Codex.AppServer.subscribe(conn, methods: ["fs/changed"])
{:ok, %{"path" => watched_path}} = Codex.AppServer.fs_watch(conn, "watch_1", "/tmp/demo.txt")

receive do
  {:codex_notification, "fs/changed", params} ->
    IO.inspect(params, label: "fs changed")
after
  5_000 ->
    IO.puts("No fs/changed notification observed")
end

{:ok, %{}} = Codex.AppServer.fs_unwatch(conn, "watch_1")

Use stable watch ids that your host can correlate back to the subscribed workflow.