All execution behavior is controlled through the AmpSdk.Types.Options struct.
For model selection specifically, Amp is payload-only in this repo today:
AmpSdk.Types.Optionscan carry a shared coremodel_payloadAmpSdk.Types.Options.validate!/1canonicalizes that payload when present- there is no separate raw model/backend option surface in
amp_sdk - if no payload is supplied, the Amp SDK does not invent a repo-local model fallback path
Options Reference
| Field | Type | Default | Description |
|---|---|---|---|
cwd | String.t() | File.cwd!() | Working directory for the Amp agent |
mode | String.t() | "smart" | Agent mode (see below) |
dangerously_allow_all | boolean() | false | Skip all permission prompts |
visibility | String.t() | "workspace" | Thread visibility |
continue_thread | boolean | String.t() | nil | Continue a thread |
settings_file | String.t() | nil | Path to settings.json |
log_level | String.t() | nil | Log level for the CLI |
log_file | String.t() | nil | Log output file path |
env | map() | %{} | Extra environment variables |
mcp_config | map() | String.t() | nil | MCP server configuration |
toolbox | String.t() | nil | Path to toolbox scripts |
skills | String.t() | nil | Path to custom skills |
permissions | [Permission.t()] | nil | Permission rules |
labels | [String.t()] | nil | Thread labels (max 20) |
thinking | boolean() | false | Use --stream-json-thinking for string prompts |
model_payload | Selection.t() | map() | nil | nil | Shared core model-selection payload |
execution_surface | ExecutionSurface.t() | map() | keyword() | nil | nil | Shared core execution surface for local or SSH placement |
stream_timeout_ms | pos_integer() | 300_000 | Stream receive timeout in milliseconds |
no_ide | boolean() | false | Disable IDE context injection (--no-ide) |
no_notifications | boolean() | false | Disable sound notifications (--no-notifications) |
no_color | boolean() | false | Disable ANSI colors (--no-color) |
no_jetbrains | boolean() | false | Disable JetBrains integration (--no-jetbrains) |
Shared Core Model Payload
When you want an explicit model selection, build it through
cli_subprocess_core and pass the resolved payload through Options:
{:ok, payload} =
CliSubprocessCore.ModelRegistry.build_arg_payload(:amp, "amp-1", [])
AmpSdk.run("Review this patch", %Options{model_payload: payload})AmpSdk.Types.Options.validate!/1 canonicalizes either a real
CliSubprocessCore.ModelRegistry.Selection or a Map.from_struct(payload)
shape back into the same selection struct. Forward-compatible extra fields stay
attached to the payload instead of being nested under :extra.
Shared Core Execution Surface
When you need SSH placement or other shared-core transport routing, pass an
execution surface through Options.execution_surface as a struct, map, or
keyword list:
alias AmpSdk.Types.Options
alias CliSubprocessCore.ExecutionSurface
surface = %ExecutionSurface{
surface_kind: :ssh_exec,
transport_options: [destination: "build-host.example"]
}
AmpSdk.run("Inspect the remote workspace", %Options{execution_surface: surface})
Amp normalizes all three public forms into the canonical shared-core struct
during `Options.validate!/1`.
On remote SSH surfaces, local `AMP_CLI_PATH` overrides are intentionally
ignored. The remote host is expected to expose `amp` on its own `PATH`, or to
receive a remote `PATH` override through `Options.env`. Missing remote binaries
surface as structured `:cli_not_found` errors with the remote stderr attached.Agent Modes
| Mode | SDK Compatible | Description |
|---|---|---|
"smart" | Yes | Default — balanced model and tool selection |
"rush" | No | Faster execution, incompatible with --stream-json |
"deep" | No | Thorough analysis, incompatible with --stream-json |
"free" | No | Interactive-only, incompatible with --execute |
Important: Only
"smart"mode supports--stream-json, which the SDK uses for bothexecute/2andrun/2. The other modes (rush,deep) are only usable via the CLI directly (for exampleamp --mode deep --execute "prompt"without--stream-json)."free"mode is interactive-only and cannot be used programmatically at all. This is a CLI restriction, not an SDK limitation.
# Default smart mode (the only mode that works with the SDK)
AmpSdk.execute("Explain this code") |> Enum.each(&handle/1)
{:ok, result} = AmpSdk.run("Explain this code")mode is passed through to the installed Amp CLI. Supported values may change as Amp evolves.
Thread Visibility
| Value | Description |
|---|---|
"private" | Only you can see the thread |
"public" | Anyone with the link can view |
"workspace" | Visible to workspace members |
"group" | Visible to group members |
Thread Continuation
# Continue the most recent thread
AmpSdk.run("Follow up", %Options{continue_thread: true})
# Continue a specific thread
AmpSdk.run("Follow up", %Options{continue_thread: "T-abc123"})MCP Server Configuration
Pass MCP server configs as a map:
mcp = %{
filesystem: %{
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem"],
env: %{}
}
}
AmpSdk.run("List files", %Options{mcp_config: mcp})Environment Variables
| Variable | Purpose |
|---|---|
AMP_CLI_PATH | Override CLI binary path |
AMP_API_KEY | Amp authentication key |
AMP_URL | Override Amp service endpoint (default: https://ampcode.com/) |
AMP_TOOLBOX | Path to toolbox scripts; prefer Options.toolbox for per-run control |
AMP_SDK_VERSION | SDK identifier (auto-set to elixir-<current package version>) |
AMP_LOG_LEVEL | Log level (alternative to --log-level flag) |
AMP_LOG_FILE | Log file path (alternative to --log-file flag) |
AMP_SETTINGS_FILE | Settings file path (alternative to --settings-file flag) |
AmpSdk.run/2 and AmpSdk.execute/2 share the same environment construction
path: explicit per-run overrides, optional :amp_sdk, :base_env application
config or caller-supplied base env maps, and automatic AMP_SDK_VERSION
injection. Provider behavior keys such as AMP_API_KEY, AMP_URL,
AMP_LOG_LEVEL, AMP_LOG_FILE, and AMP_SETTINGS_FILE are not ambiently
forwarded by the runtime path. Pass provider behavior environment explicitly
through Options.env or the typed option when applicable.
Governed execution is a separate mode selected by explicit authority. It
rejects Options.env, AMP_CLI_PATH, AMP_API_KEY, AMP_URL, log/settings
file paths, permissions/skills settings, MCP config, MCP OAuth credential
options, cwd overrides, and execution-surface overrides. The governed process
receives only the authority-materialized command, cwd, and env.
Additional env vars per execution:
AmpSdk.run("check env", %Options{env: %{"MY_VAR" => "value"}})nil values in Options.env are dropped during normalization (they are not coerced into empty-string values).
Headless Flags
Control IDE, notification, color, and JetBrains integration:
AmpSdk.run("task", %Options{
no_ide: true, # --no-ide (disable IDE file inclusion)
no_notifications: true, # --no-notifications (silence sounds)
no_color: true, # --no-color (plain text output)
no_jetbrains: true # --no-jetbrains (disable JetBrains)
})These default to false. Set to true for headless/CI environments.
Option Key Normalization
When building MCP structs from maps/keywords, use atom keys for option fields.
# Valid: atom keys
AmpSdk.Types.MCPStdioServer.new(%{command: "npx", args: ["-y", "tool"]})String keys are ignored by these constructors. If you already have JSON-style string keys, pass Options.mcp_config as a JSON string instead of a map.
For MCP constructors, nil values inside env and headers maps are dropped during normalization.
Thinking Mode
Include the model's chain-of-thought reasoning in responses:
AmpSdk.execute("Explain this code", %Options{thinking: true})
|> Enum.each(fn
%AmpSdk.Types.AssistantMessage{message: %{content: content}} ->
for %AmpSdk.Types.ThinkingContent{thinking: t} <- content, do: IO.puts("[think] #{t}")
for %AmpSdk.Types.TextContent{text: t} <- content, do: IO.write(t)
_ -> :ok
end)CLI Discovery
The SDK locates the Amp CLI by checking (in order):
- Materialized
AMP_CLI_PATHfrom:cli_subprocess_core, :provider_cli_env ~/.amp/bin/amp~/.local/bin/amp- System
PATH
This discovery order is standalone direct-use behavior only. Governed execution bypasses it and launches the authority-materialized command.
Top-level applications that want to honor OS environment variables should read
them in config/runtime.exs or another configuration boundary and put the
resulting map in :cli_subprocess_core, :provider_cli_env; amp_sdk runtime
modules do not call System.get_env/1.
Use AmpSdk.CLI.resolve/1 to inspect the command spec:
{:ok, spec} = AmpSdk.CLI.resolve()
IO.inspect(spec.program, label: "program")
IO.inspect(spec.argv_prefix, label: "argv prefix")Advanced CLI Settings via settings_file
The Amp CLI supports many settings beyond what the SDK exposes as Options fields. You can access all of them by pointing Options.settings_file to a JSON file:
AmpSdk.run("task", %Options{settings_file: "/path/to/settings.json"})When you also provide Options.permissions or Options.skills, the SDK merges those into your settings file automatically.
Available Settings
These are the amp. prefix keys recognized by the CLI. All can be set in the settings JSON:
| Setting | Type | Description |
|---|---|---|
amp.proxy | string | HTTP/HTTPS proxy URL for requests to Amp servers |
amp.network.timeout | integer | Seconds to wait for network requests before timeout |
amp.tools.disable | [string] | Tool names to disable (use builtin:name to target only builtins) |
amp.tools.enable | [string] | Glob patterns of tools to enable (if set, only matching tools are active) |
amp.guardedFiles.allowlist | [string] | File glob patterns allowed without confirmation (overrides built-in denylist) |
amp.mcpServers | object | MCP server configurations (alternative to Options.mcp_config) |
amp.permissions | [object] | Permission rules (alternative to Options.permissions) |
amp.dangerouslyAllowAll | boolean | Skip all prompts (alternative to Options.dangerously_allow_all) |
amp.skills.path | string | Path to custom skills (alternative to Options.skills) |
amp.toolbox.path | string | Path to toolbox scripts (alternative to Options.toolbox) |
amp.notifications.enabled | boolean | Enable sound notifications |
amp.notifications.system.enabled | boolean | Enable system notifications when terminal unfocused |
amp.git.commit.coauthor.enabled | boolean | Add Amp as co-author in git commits |
amp.git.commit.ampThread.enabled | boolean | Add Amp-Thread trailer in git commits |
amp.showCosts | boolean | Show cost tracking during thread execution |
amp.fuzzy.alwaysIncludePaths | [string] | Globs always included in fuzzy file search (even if gitignored) |
amp.bitbucketToken | string | Personal access token for Bitbucket Enterprise |
amp.experimental.modes | [string] | Enable experimental agent modes by name |
Example: Enterprise Configuration
# Write a settings file for enterprise use
settings = %{
"amp.proxy" => "http://proxy.corp.example.com:8080",
"amp.network.timeout" => 60,
"amp.tools.disable" => ["browser_navigate"],
"amp.guardedFiles.allowlist" => ["config/**"],
"amp.git.commit.coauthor.enabled" => true
}
path = Path.join(System.tmp_dir!(), "amp-settings.json")
File.write!(path, Jason.encode!(settings))
{:ok, result} = AmpSdk.run("Review the code", %Options{settings_file: path})