# `Codex.AppServer`
[🔗](https://github.com/nshkrdotcom/codex_sdk/blob/v0.18.0/lib/codex/app_server.ex#L1)

App-server transport for stateful, bidirectional communication with Codex.

# `connect_opts`

```elixir
@type connect_opts() :: [
  init_timeout_ms: pos_integer(),
  client_name: String.t(),
  client_title: String.t(),
  client_version: String.t(),
  experimental_api: boolean(),
  execution_surface: CliSubprocessCore.ExecutionSurface.t() | map() | keyword(),
  cwd: String.t(),
  process_env: map() | keyword(),
  env: map() | keyword(),
  oauth: keyword()
]
```

Options for launching and initializing a managed `codex app-server` child process.

`cwd` and `process_env` / `env` apply to the child process itself. Per-thread working
directories still belong on `thread/start`, `thread/resume`, or `Codex.Thread.Options`.

# `connect_remote_opts`

```elixir
@type connect_remote_opts() :: [
  init_timeout_ms: pos_integer(),
  client_name: String.t(),
  client_title: String.t(),
  client_version: String.t(),
  experimental_api: boolean(),
  auth_token: String.t(),
  auth_token_env: String.t(),
  governed_authority: map() | keyword(),
  cwd: String.t(),
  process_env: map() | keyword(),
  env: map() | keyword(),
  oauth: keyword()
]
```

# `connection`

```elixir
@type connection() :: pid()
```

# `alive?`

```elixir
@spec alive?(connection()) :: boolean()
```

# `apps_list`

```elixir
@spec apps_list(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

Lists available apps/connectors.

# `collaboration_mode_list`

```elixir
@spec collaboration_mode_list(connection()) :: {:ok, map()} | {:error, term()}
```

Lists collaboration mode presets (experimental).

# `command_exec`

```elixir
@spec command_exec(connection(), [String.t()], keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `command_exec_resize`

```elixir
@spec command_exec_resize(connection(), String.t(), map() | keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `command_exec_terminate`

```elixir
@spec command_exec_terminate(connection(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

# `command_exec_write`

```elixir
@spec command_exec_write(connection(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

Writes bytes to a running `command/exec` session.

# `command_write_stdin`

```elixir
@spec command_write_stdin(connection(), String.t(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

Backwards-compatible alias for `command_exec_write/3` using raw stdin text.

# `config_batch_write`

```elixir
@spec config_batch_write(connection(), [map()], keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `config_read`

```elixir
@spec config_read(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

# `config_requirements`

```elixir
@spec config_requirements(connection()) :: {:ok, map()} | {:error, term()}
```

Reads config requirements enforced by the server (if any).

# `config_write`

```elixir
@spec config_write(connection(), String.t(), term(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `connect`

```elixir
@spec connect(Codex.Options.t(), connect_opts()) ::
  {:ok, connection()} | {:error, term()}
```

Starts a supervised `codex app-server` subprocess and completes the `initialize` handshake.

Use `cwd` and `process_env` (or the `env` alias) when the app-server child must run with an
isolated working directory or `CODEX_HOME` without mutating the caller's shell environment.

# `connect_remote`

```elixir
@spec connect_remote(String.t(), connect_remote_opts()) ::
  {:ok, connection()} | {:error, term()}
```

Connects to a remote websocket-backed app-server endpoint and completes the
`initialize` handshake.

# `device_key_create`

```elixir
@spec device_key_create(connection(), map() | keyword()) ::
  {:ok, map()} | {:error, term()}
```

Creates a controller-local device key.

# `device_key_public`

```elixir
@spec device_key_public(connection(), String.t()) :: {:ok, map()} | {:error, term()}
```

Reads device-key public metadata by key id.

# `device_key_sign`

```elixir
@spec device_key_sign(connection(), String.t(), map()) ::
  {:ok, map()} | {:error, term()}
```

Signs a structured device-key payload with a controller-local key.

# `disconnect`

```elixir
@spec disconnect(connection()) :: :ok
```

# `environment_add`

```elixir
@spec environment_add(connection(), String.t(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

Registers an execution environment backed by an exec-server websocket.

# `environment_info`

```elixir
@spec environment_info(connection(), String.t()) :: {:ok, map()} | {:error, term()}
```

Reads shell and cwd metadata for a registered execution environment.

# `experimental_feature_enablement_set`

```elixir
@spec experimental_feature_enablement_set(connection(), map() | keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `experimental_feature_list`

```elixir
@spec experimental_feature_list(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

# `external_agent_config_detect`

```elixir
@spec external_agent_config_detect(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

# `external_agent_config_import`

```elixir
@spec external_agent_config_import(connection(), [map()]) ::
  {:ok, map()} | {:error, term()}
```

# `feedback_upload`

```elixir
@spec feedback_upload(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

# `fs_copy`

```elixir
@spec fs_copy(connection(), String.t(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

Copies a file or directory via the app-server filesystem API.

# `fs_create_directory`

```elixir
@spec fs_create_directory(connection(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

Creates a directory via the app-server filesystem API.

# `fs_get_metadata`

```elixir
@spec fs_get_metadata(connection(), String.t()) :: {:ok, map()} | {:error, term()}
```

Fetches file or directory metadata via the app-server filesystem API.

# `fs_read_directory`

```elixir
@spec fs_read_directory(connection(), String.t()) :: {:ok, map()} | {:error, term()}
```

Lists directory entries via the app-server filesystem API.

# `fs_read_file`

```elixir
@spec fs_read_file(connection(), String.t()) :: {:ok, map()} | {:error, term()}
```

Reads a file via the app-server filesystem API, returning a base64 payload.

# `fs_remove`

```elixir
@spec fs_remove(connection(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

Removes a file or directory via the app-server filesystem API.

# `fs_unwatch`

```elixir
@spec fs_unwatch(connection(), String.t()) :: {:ok, map()} | {:error, term()}
```

Stops a prior filesystem watch.

# `fs_watch`

```elixir
@spec fs_watch(connection(), String.t(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

Starts filesystem change notifications for an absolute file or directory path.

# `fs_write_file`

```elixir
@spec fs_write_file(connection(), String.t(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

Writes base64-encoded file contents via the app-server filesystem API.

# `fuzzy_file_search`

```elixir
@spec fuzzy_file_search(connection(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `fuzzy_file_search_session_start`

```elixir
@spec fuzzy_file_search_session_start(connection(), String.t(), [String.t()]) ::
  {:ok, map()} | {:error, term()}
```

# `fuzzy_file_search_session_stop`

```elixir
@spec fuzzy_file_search_session_stop(connection(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

# `fuzzy_file_search_session_update`

```elixir
@spec fuzzy_file_search_session_update(connection(), String.t(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

# `marketplace_add`

```elixir
@spec marketplace_add(connection(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

Adds a marketplace source through the app-server marketplace API.

# `marketplace_remove`

```elixir
@spec marketplace_remove(connection(), String.t()) :: {:ok, map()} | {:error, term()}
```

Removes an installed marketplace by name.

# `marketplace_upgrade`

```elixir
@spec marketplace_upgrade(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

Upgrades one installed marketplace or all marketplaces when no name is provided.

# `memory_reset`

```elixir
@spec memory_reset(connection()) :: {:ok, map()} | {:error, term()}
```

# `model_list`

```elixir
@spec model_list(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

# `model_provider_capabilities_read`

```elixir
@spec model_provider_capabilities_read(connection()) ::
  {:ok, map()} | {:error, term()}
```

Reads the active model provider's capability flags (namespace tools, image
generation, web search).

# `permission_profile_list`

```elixir
@spec permission_profile_list(connection(), map() | keyword()) ::
  {:ok, map()} | {:error, term()}
```

Lists available named permission profiles (id, description, allowed status).

# `plugin_install`

```elixir
@spec plugin_install(connection(), String.t(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

Installs a plugin via the app-server plugin API and returns the raw response map.

For typed structs, use `plugin_install_typed/4`.

# `plugin_install_typed`

```elixir
@spec plugin_install_typed(connection(), String.t(), String.t(), keyword()) ::
  {:ok, Codex.Protocol.Plugin.InstallResponse.t()} | {:error, term()}
```

Installs a plugin via the app-server plugin API and parses the response into
`Codex.Protocol.Plugin.InstallResponse`.

The raw `plugin_install/4` wrapper remains available and still returns the
original map payload.

# `plugin_list`

```elixir
@spec plugin_list(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

Lists plugin marketplaces via the app-server plugin API and returns the raw response map.

For typed structs, use `plugin_list_typed/2`.

# `plugin_list_typed`

```elixir
@spec plugin_list_typed(
  connection(),
  keyword()
) :: {:ok, Codex.Protocol.Plugin.ListResponse.t()} | {:error, term()}
```

Lists plugin marketplaces via the app-server plugin API and parses the response
into `Codex.Protocol.Plugin.ListResponse`.

The raw `plugin_list/2` wrapper remains available and still returns the
original map payload.

# `plugin_read`

```elixir
@spec plugin_read(connection(), String.t(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

Reads plugin details from a marketplace entry via the app-server plugin API
and returns the raw response map.

For typed structs, use `plugin_read_typed/3`.

# `plugin_read_typed`

```elixir
@spec plugin_read_typed(connection(), String.t(), String.t()) ::
  {:ok, Codex.Protocol.Plugin.ReadResponse.t()} | {:error, term()}
```

Reads plugin details from a marketplace entry via the app-server plugin API
and parses the response into `Codex.Protocol.Plugin.ReadResponse`.

The raw `plugin_read/3` wrapper remains available and still returns the
original map payload.

# `plugin_uninstall`

```elixir
@spec plugin_uninstall(connection(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

Uninstalls a plugin via the app-server plugin API and returns the raw response map.

For typed structs, use `plugin_uninstall_typed/3`.

# `plugin_uninstall_typed`

```elixir
@spec plugin_uninstall_typed(connection(), String.t(), keyword()) ::
  {:ok, Codex.Protocol.Plugin.UninstallResponse.t()} | {:error, term()}
```

Uninstalls a plugin via the app-server plugin API and parses the response into
`Codex.Protocol.Plugin.UninstallResponse`.

The raw `plugin_uninstall/3` wrapper remains available and still returns the
original map payload.

# `request_typed`

```elixir
@spec request_typed(
  connection(),
  String.t(),
  map() | keyword() | struct() | nil,
  module(),
  keyword()
) :: {:ok, struct()} | {:error, term()}
```

Sends an app-server request and parses the response with a typed response module.

When `params` is a typed params struct, the struct module's `to_map/1` is used
for wire encoding. For the typed plugin APIs, plain maps and keywords are
normalized through the matching `Codex.Protocol.Plugin.*Params` module before
the request is sent.

# `respond`

```elixir
@spec respond(connection(), String.t() | integer(), map()) :: :ok | {:error, term()}
```

# `review_start`

```elixir
@spec review_start(connection(), String.t(), term(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `skills_config_write`

```elixir
@spec skills_config_write(connection(), String.t(), boolean()) ::
  {:ok, map()} | {:error, term()}
```

Writes a skills config entry enabling or disabling a skill by path.

# `skills_list`

```elixir
@spec skills_list(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

# `skills_remote_export`

```elixir
@spec skills_remote_export(connection(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

# `skills_remote_list`

```elixir
@spec skills_remote_list(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

# `subscribe`

```elixir
@spec subscribe(
  connection(),
  keyword()
) :: :ok | {:error, term()}
```

# `thread_archive`

```elixir
@spec thread_archive(connection(), String.t()) :: :ok | {:error, term()}
```

# `thread_background_terminals_clean`

```elixir
@spec thread_background_terminals_clean(connection(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_background_terminals_list`

```elixir
@spec thread_background_terminals_list(connection(), String.t(), map() | keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_background_terminals_terminate`

```elixir
@spec thread_background_terminals_terminate(connection(), String.t(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_compact`

```elixir
@spec thread_compact(connection(), String.t()) :: {:ok, map()} | {:error, term()}
```

Starts server-side context compaction for a thread.

# `thread_compact_start`

```elixir
@spec thread_compact_start(connection(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

Explicit alias for `thread_compact/2`.

# `thread_delete`

```elixir
@spec thread_delete(connection(), String.t()) :: {:ok, map()} | {:error, term()}
```

# `thread_fork`

```elixir
@spec thread_fork(connection(), String.t(), map() | keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_inject_items`

```elixir
@spec thread_inject_items(connection(), String.t(), [map()]) ::
  {:ok, map()} | {:error, term()}
```

# `thread_items_list`

```elixir
@spec thread_items_list(connection(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_list`

```elixir
@spec thread_list(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

# `thread_loaded_list`

```elixir
@spec thread_loaded_list(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

# `thread_memory_mode_set`

```elixir
@spec thread_memory_mode_set(connection(), String.t(), atom() | String.t()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_metadata_update`

```elixir
@spec thread_metadata_update(connection(), String.t(), map() | keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_name_set`

```elixir
@spec thread_name_set(connection(), String.t(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_read`

```elixir
@spec thread_read(connection(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_realtime_append_audio`

```elixir
@spec thread_realtime_append_audio(connection(), String.t(), map() | keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_realtime_append_speech`

```elixir
@spec thread_realtime_append_speech(connection(), String.t(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_realtime_append_text`

```elixir
@spec thread_realtime_append_text(connection(), String.t(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_realtime_list_voices`

```elixir
@spec thread_realtime_list_voices(connection()) :: {:ok, map()} | {:error, term()}
```

# `thread_realtime_start`

```elixir
@spec thread_realtime_start(connection(), String.t(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_realtime_stop`

```elixir
@spec thread_realtime_stop(connection(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_resume`

```elixir
@spec thread_resume(connection(), String.t(), map() | keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_rollback`

```elixir
@spec thread_rollback(connection(), String.t(), pos_integer()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_search`

```elixir
@spec thread_search(
  connection(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

# `thread_search`

```elixir
@spec thread_search(connection(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_settings_update`

```elixir
@spec thread_settings_update(connection(), String.t(), map() | keyword()) ::
  {:ok, map()} | {:error, term()}
```

Updates persistent settings for subsequent turns on a thread.

Accepts `cwd`, `approval_policy`, `approvals_reviewer`, `sandbox_policy`,
`permissions`, `model`, `service_tier` (double-option: omit to leave
unchanged, pass `nil`/`:clear` to explicitly clear it), `effort`, `summary`,
and `collaboration_mode`. The app-server only acknowledges the update is
queued; wait for the `thread/settings/updated` notification for the
applied result.

# `thread_shell_command`

```elixir
@spec thread_shell_command(connection(), String.t(), String.t()) ::
  {:ok, map()} | {:error, term()}
```

Runs a thread-bound shell command via the app-server `!` workflow.

# `thread_start`

```elixir
@spec thread_start(connection(), map() | keyword()) :: {:ok, map()} | {:error, term()}
```

# `thread_turns_list`

```elixir
@spec thread_turns_list(connection(), String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `thread_unarchive`

```elixir
@spec thread_unarchive(connection(), String.t()) :: {:ok, map()} | {:error, term()}
```

# `thread_unsubscribe`

```elixir
@spec thread_unsubscribe(connection(), String.t()) :: {:ok, map()} | {:error, term()}
```

# `turn_interrupt`

```elixir
@spec turn_interrupt(connection(), String.t(), String.t()) :: :ok | {:error, term()}
```

# `turn_start`

```elixir
@spec turn_start(connection(), String.t(), String.t() | [map()], keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `turn_steer`

```elixir
@spec turn_steer(connection(), String.t(), String.t() | [map()], keyword()) ::
  {:ok, map()} | {:error, term()}
```

# `unsubscribe`

```elixir
@spec unsubscribe(connection()) :: :ok
```

# `windows_sandbox_setup_start`

```elixir
@spec windows_sandbox_setup_start(connection(), atom() | String.t(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
