### Installing and uninstalling Source: https://github.com/guess/claude_code/blob/main/docs/guides/plugins.md Examples of installing and uninstalling plugins. ```elixir # Install from a marketplace {:ok, _} = ClaudeCode.Plugin.install("code-simplifier@claude-plugins-official") # Install with a specific scope {:ok, _} = ClaudeCode.Plugin.install("my-plugin@my-org", scope: :project) # Uninstall {:ok, _} = ClaudeCode.Plugin.uninstall("code-simplifier@claude-plugins-official") ``` -------------------------------- ### Quick start example Source: https://github.com/guess/claude_code/blob/main/docs/guides/structured-outputs.md Demonstrates how to define a JSON Schema and use it with the ClaudeCode.query function to get structured output. ```elixir # Define the shape of data you want back schema = %{ "type" => "object", "properties" => %{ "company_name" => %{"type" => "string"}, "founded_year" => %{"type" => "number"}, "headquarters" => %{"type" => "string"} }, "required" => ["company_name"] } {:ok, result} = ClaudeCode.query( "Research Anthropic and provide key company information", output_format: %{type: :json_schema, schema: schema} ) # The result message contains structured_output with validated data result.structured_output # => %{"company_name" => "Anthropic", "founded_year" => 2021, "headquarters" => "San Francisco, CA"} ``` -------------------------------- ### Starting a subprocess MCP server Source: https://github.com/guess/claude_code/blob/main/docs/guides/custom-tools.md Example of starting a full MCP server as a stdio subprocess. ```elixir {:ok, session} = ClaudeCode.start_link( mcp_servers: %{ "my-server" => MyApp.MCPServer } ) ``` -------------------------------- ### Start Session with Inherited Environment Source: https://github.com/guess/claude_code/blob/main/docs/guides/hosting.md Example of starting a ClaudeCode session with specific environment variables inherited. ```elixir {:ok, session} = ClaudeCode.start_link( inherit_env: ["PATH", "HOME", "LANG", {:prefix, "ANTHROPIC_"}, {:prefix, "HTTP_"}], api_key: System.get_env("ANTHROPIC_API_KEY") ) ``` -------------------------------- ### Quick Start Source: https://github.com/guess/claude_code/blob/main/docs/guides/distributed-sessions.md Example of starting a distributed session and streaming a message. ```elixir # On the remote node (already running as claude@gpu-server): # Ensure claude_code is in deps and CLI is installed # On your local node: {:ok, session} = ClaudeCode.start_link( cwd: "/workspaces/my-project", model: "claude-sonnet-4-20250514", adapter: {ClaudeCode.Adapter.Node, [ node: :"claude@gpu-server" ]}) # Works identically to a local session response = session |> ClaudeCode.stream("Hello from across the cluster!") |> ClaudeCode.Stream.final_text() ``` -------------------------------- ### Verifying plugin installation Source: https://github.com/guess/claude_code/blob/main/docs/guides/plugins.md Code example to verify plugin installation by inspecting the system initialization message, checking loaded plugins and available slash commands. ```elixir alias ClaudeCode.Message.SystemMessage session |> ClaudeCode.stream("Hello", plugins: [%{type: :local, path: "./my-plugin"}] ) |> ClaudeCode.Stream.filter_type(:system) |> Enum.each(fn %SystemMessage{subtype: :init, plugins: plugins, slash_commands: commands} -> # Check loaded plugins IO.puts("Loaded plugins:") Enum.each(plugins, fn %{name: name, path: path} -> IO.puts(" #{name} (#{path})") name when is_binary(name) -> IO.puts(" #{name}") end) # Check available commands (plugins add namespaced commands) IO.puts("Available commands:") Enum.each(commands, &IO.puts(" #{&1}")) _ -> :ok end) ``` -------------------------------- ### Listing installed plugins Source: https://github.com/guess/claude_code/blob/main/docs/guides/plugins.md Example of listing installed plugins using ClaudeCode.Plugin.list(). ```elixir {:ok, plugins} = ClaudeCode.Plugin.list() Enum.each(plugins, fn plugin -> IO.puts("#{plugin.id} v#{plugin.version} (#{plugin.scope}, enabled: #{plugin.enabled})") end) ``` -------------------------------- ### Start the Ownership Server Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Add ClaudeCode.Test to your test helper. ```elixir # test/test_helper.exs ExUnit.start() Supervisor.start_link([ClaudeCode.Test], strategy: :one_for_one) ``` -------------------------------- ### Quickstart Example Source: https://github.com/guess/claude_code/blob/main/docs/guides/mcp.md Connects to the Claude Code documentation MCP server using HTTP transport and allows all tools from the server with a wildcard. ```elixir {:ok, result} = ClaudeCode.query( "Use the docs MCP server to explain what hooks are in Claude Code", mcp_servers: %{ "claude-code-docs" => %{ type: "http", url: "https://code.claude.com/docs/mcp" } }, allowed_tools: ["mcp__claude-code-docs__*"] ) ``` -------------------------------- ### Session-level system prompts example Source: https://github.com/guess/claude_code/blob/main/docs/guides/modifying-system-prompts.md Examples of starting separate sessions with different system prompts. ```elixir {:ok, reviewer} = ClaudeCode.start_link( system_prompt: "You are a security auditor. Focus on OWASP vulnerabilities." ) {:ok, assistant} = ClaudeCode.start_link( append_system_prompt: "You are a general coding assistant." ) ``` -------------------------------- ### Installation Commands Source: https://github.com/guess/claude_code/blob/main/README.md Commands to get dependencies and optionally install the CLI binary. ```bash mix deps.get mix claude_code.install # optional – downloads on first use if skipped ``` -------------------------------- ### Complete example Source: https://github.com/guess/claude_code/blob/main/docs/guides/plugins.md A full example demonstrating plugin loading and usage. ```elixir alias ClaudeCode.Message.{SystemMessage, ResultMessage} plugin_path = Path.join([__DIR__, "plugins", "my-plugin"]) {:ok, session} = ClaudeCode.start_link( plugins: [%{type: :local, path: plugin_path}], max_turns: 3 ) session |> ClaudeCode.stream("What custom commands do you have available?") |> Enum.each(fn %SystemMessage{subtype: :init, plugins: plugins, slash_commands: commands} -> IO.puts("Loaded plugins: #{inspect(plugins)}") IO.puts("Available commands: #{inspect(commands)}") %ResultMessage{result: text} -> IO.puts("Result: #{text}") _ -> :ok end) ``` -------------------------------- ### Allowing Spawned Processes Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Example demonstrating how to allow a spawned process to access stubs in ClaudeCode testing. ```elixir test "spawned process can use stub" do ClaudeCode.Test.stub(ClaudeCode, fn _, _ -> [ClaudeCode.Test.text("Hello")] end) task = Task.async(fn -> {:ok, session} = ClaudeCode.start_link() ClaudeCode.stream(session, "hi") |> Enum.to_list() end) # Allow the task to access our stubs ClaudeCode.Test.allow(ClaudeCode, self(), task.pid) messages = Task.await(task) assert length(messages) > 0 end ``` -------------------------------- ### Starting a session with a specific permission mode Source: https://github.com/guess/claude_code/blob/main/docs/guides/permissions.md Example of starting a ClaudeCode session and setting the permission mode to `:accept_edits`. ```elixir {:ok, session} = ClaudeCode.start_link( permission_mode: :accept_edits ) ``` -------------------------------- ### Tool Use Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Examples of creating tool use messages. ```elixir # Tool invocation ClaudeCode.Test.tool_use("Read", %{file_path: "/tmp/file.txt"}) # With preceding text ClaudeCode.Test.tool_use("Bash", %{command: "ls -la"}, text: "Let me check the directory...") ``` -------------------------------- ### Settings configuration example (map) Source: https://github.com/guess/claude_code/blob/main/docs/guides/modifying-system-prompts.md Example of passing settings directly as a map using the :settings option. ```elixir {:ok, session} = ClaudeCode.start_link( settings: %{ "preferredLanguage" => "elixir", "codeStyle" => "functional" } ) ``` -------------------------------- ### Default run command Source: https://github.com/guess/claude_code/blob/main/examples/README.md Runs the streaming and character streaming examples using the default bundled CLI configuration. ```bash mix run examples/streaming_example.exs mix run examples/character_streaming_example.exs ``` -------------------------------- ### Configure hooks Source: https://github.com/guess/claude_code/blob/main/docs/guides/hooks.md Example of how to pass hooks in the `:hooks` option when starting a session in Elixir. ```elixir {:ok, session} = ClaudeCode.start_link( hooks: %{ PreToolUse: [%{matcher: "Bash", hooks: [MyApp.BashAuditor]}] } ) ``` -------------------------------- ### Concurrent Tests Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Example demonstrating concurrent test execution with `async: true`. ```elixir defmodule MyAppTest do use ExUnit.Case, async: true test "concurrent test 1" do ClaudeCode.Test.stub(ClaudeCode, fn _, _ -> [ClaudeCode.Test.text("Response 1")] end) # ... end test "concurrent test 2" do ClaudeCode.Test.stub(ClaudeCode, fn _, _ -> [ClaudeCode.Test.text("Response 2")] end) # ... end end ``` -------------------------------- ### Development and testing Source: https://github.com/guess/claude_code/blob/main/docs/guides/plugins.md Example of loading plugins during development without installing them globally. ```elixir {:ok, session} = ClaudeCode.start_link( plugins: [%{type: :local, path: "./dev-plugins/my-plugin"}] ) ``` -------------------------------- ### Per-User Sessions in Elixir LiveView Source: https://github.com/guess/claude_code/blob/main/docs/guides/hosting.md Example of starting a session linked to a LiveView process for multi-turn conversations, ensuring automatic cleanup when the parent process dies. ```elixir defmodule MyAppWeb.ChatLive do use MyAppWeb, :live_view def mount(_params, _session, socket) do {:ok, session} = ClaudeCode.start_link( system_prompt: "You are a helpful assistant.", include_partial_messages: true ) {:ok, assign(socket, claude: session)} end def handle_event("send", %{"message" => msg}, socket) do Task.start(fn -> socket.assigns.claude |> ClaudeCode.stream(msg) |> ClaudeCode.Stream.text_deltas() |> Enum.each(&send(socket.root_pid, {:chunk, &1})) send(socket.root_pid, :stream_done) end) {:noreply, socket} end def handle_info({:chunk, chunk}, socket) do {:noreply, assign(socket, response: socket.assigns.response <> chunk)} end def handle_info(:stream_done, socket) do {:noreply, assign(socket, streaming: false)} end end ``` -------------------------------- ### Testing Tool Sequences Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Example test for handling a sequence of tool interactions. ```elixir test "handles file read and edit sequence" do ClaudeCode.Test.stub(ClaudeCode, fn _query, _opts -> [ ClaudeCode.Test.text("I'll read the file first"), ClaudeCode.Test.tool_use("Read", %{file_path: "lib/app.ex"}), ClaudeCode.Test.tool_result("defmodule App do\nend"), ClaudeCode.Test.text("Now I'll edit it"), ClaudeCode.Test.tool_use("Edit", %{ file_path: "lib/app.ex", old_string: "defmodule App do", new_string: "defmodule MyApp do" }), ClaudeCode.Test.tool_result("File updated"), ClaudeCode.Test.text("Done! I renamed the module."), ClaudeCode.Test.result("Done! I renamed the module.") ] end) {:ok, session} = ClaudeCode.start_link() summary = session |> ClaudeCode.stream("Rename the module") |> ClaudeCode.Stream.collect() assert length(summary.tool_calls) == 2 assert summary.result == "Done! I renamed the module." end ``` -------------------------------- ### Multiple Tools Example Source: https://github.com/guess/claude_code/blob/main/docs/guides/custom-tools.md Example demonstrating how to selectively allow multiple tools from an MCP server. ```elixir defmodule MyApp.Utilities do use ClaudeCode.MCP.Server, name: "utilities" tool :calculate do description "Perform calculations" field :expression, :string, required: true def execute(%{expression: expr}), do: {:ok, "#{Code.eval_string(expr) |> elem(0)}"} end tool :translate do description "Translate text" field :text, :string, required: true field :target_lang, :string, required: true def execute(%{text: text, target_lang: lang}), do: {:ok, "Translated #{text} to #{lang}"} end tool :search_web do description "Search the web" field :query, :string, required: true def execute(%{query: query}), do: {:ok, "Results for: #{query}"} end end {:ok, result} = ClaudeCode.query( "Calculate 5 + 3 and translate 'hello' to Spanish", mcp_servers: %{"utilities" => MyApp.Utilities}, allowed_tools: [ "mcp__utilities__calculate", # Allow calculator "mcp__utilities__translate" # Allow translator # mcp__utilities__search_web is NOT allowed ] ) ``` -------------------------------- ### Session options example Source: https://github.com/guess/claude_code/blob/main/docs/guides/distributed-sessions.md Example demonstrating various session options including adapter configuration for a distributed session. ```elixir {:ok, session} = ClaudeCode.start_link( name: :remote_claude, cwd: "/workspaces/project", model: "claude-sonnet-4-20250514", permission_mode: :dont_ask, allowed_tools: ["Read", "Glob", "Grep"], adapter: {ClaudeCode.Adapter.Node, [ node: :"claude@gpu-server" ]}) ``` -------------------------------- ### Example CLAUDE.md Source: https://github.com/guess/claude_code/blob/main/docs/guides/modifying-system-prompts.md An example of a CLAUDE.md file with project guidelines for code style, testing, and commands. ```markdown # Project Guidelines ## Code Style - Use Elixir 1.18+ features - Prefer pattern matching over conditionals - Always include @moduledoc and @doc attributes ## Testing - Run `mix test` before committing - Maintain >80% code coverage - Use ExUnit with Mox for mocking ## Commands - Quality checks: `mix quality` - Dev server: `iex -S phx.server` - Type check: `mix dialyzer` ``` -------------------------------- ### Can Use Tool Example Source: https://github.com/guess/claude_code/blob/main/docs/guides/hooks.md This example demonstrates how to use the :can_use_tool option to define a permission callback. ```elixir defmodule MyApp.ToolPermissions do @behaviour ClaudeCode.Hook @impl true def call(%{tool_name: "Bash", input: %{"command" => cmd}}, _tool_use_id) do cond do String.contains?(cmd, "rm -rf") -> {:deny, message: "Destructive command blocked"} String.starts_with?(cmd, "sudo") -> {:deny, message: "No sudo allowed"} true -> :allow end end def call(_input, _tool_use_id), do: :allow end {:ok, session} = ClaudeCode.start_link(can_use_tool: MyApp.ToolPermissions) ``` -------------------------------- ### Basic Usage Source: https://github.com/guess/claude_code/blob/main/README.md A simple example demonstrating how to start a session, stream a message, and extract text content. ```elixir {:ok, session} = ClaudeCode.start_link() session |> ClaudeCode.stream("Refactor the auth module and add tests") |> ClaudeCode.Stream.text_content() |> Enum.each(&IO.write/1) ``` -------------------------------- ### MCP Integration Example Source: https://github.com/guess/claude_code/blob/main/README.md Starts a session with multiple MCP server types (in-process, stdio, HTTP). ```elixir {:ok, session} = ClaudeCode.start_link( mcp_servers: %{ "app-tools" => MyApp.Tools, # In-process "github" => %{command: "npx", args: ["-y", "@modelcontextprotocol/server-github"], env: %{"GITHUB_TOKEN" => System.get_env("GITHUB_TOKEN")}}, "docs" => %{type: "http", url: "https://code.claude.com/docs/mcp"} # HTTP }, allowed_tools: ["mcp__app-tools__*", "mcp__github__*", "mcp__docs__*"] ) ``` -------------------------------- ### Ephemeral Sessions with ClaudeCode.query/2 Source: https://github.com/guess/claude_code/blob/main/docs/guides/hosting.md Example of using `ClaudeCode.query/2` for stateless one-off work, which starts a session, runs the query, and stops the session automatically. ```elixir {:ok, result} = ClaudeCode.query("Summarize this PR", allowed_tools: ["Read", "Grep"] ) ``` -------------------------------- ### Output Style Markdown Example Source: https://github.com/guess/claude_code/blob/main/docs/guides/modifying-system-prompts.md An example of an output style markdown file with YAML frontmatter. ```markdown --- name: Code Reviewer description: Thorough code review assistant keep-coding-instructions: true --- You are an expert code reviewer. For every code submission: 1. Check for bugs and security issues 2. Evaluate performance 3. Suggest improvements 4. Rate code quality (1-10) ``` -------------------------------- ### Testing Error Handling Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Example demonstrating how to test graceful handling of API errors, such as rate limits, by stubbing an error result. ```elixir test "handles API errors gracefully" do ClaudeCode.Test.stub(ClaudeCode, fn _, _ -> [ClaudeCode.Test.result("Rate limit exceeded", is_error: true)] end) {:ok, session} = ClaudeCode.start_link() result = session |> ClaudeCode.stream("test") |> Enum.find(&match?(%ClaudeCode.Message.ResultMessage{}, &1)) assert result.is_error == true end ``` -------------------------------- ### Handle MCP server initialization errors Source: https://github.com/guess/claude_code/blob/main/docs/guides/mcp.md This example shows how to handle errors during MCP server initialization. The SDK emits a SystemMessage with subtype :init, which includes the connection status for each MCP server. This allows you to detect connection failures before the agent starts working. ```elixir alias ClaudeCode.Message.{SystemMessage, ResultMessage} session |> ClaudeCode.stream("Process data") |> Enum.each(fn %SystemMessage{subtype: :init} = msg -> IO.inspect(msg, label: "System init") %ResultMessage{is_error: true, subtype: subtype} -> IO.puts("Execution failed: #{subtype}") _ -> :ok end) ``` -------------------------------- ### Install dependencies Source: https://github.com/guess/claude_code/blob/main/docs/guides/distributed-sessions.md Instructions for installing dependencies on the remote node, including adding `claude_code` to `mix.exs` and installing the CLI binary. ```bash # In your remote application's mix.exs, add: # {:claude_code, ">~> 0.36"} # Then install the CLI mix deps.get mix claude_code.install ``` -------------------------------- ### Sandbox Runtime Installation Source: https://github.com/guess/claude_code/blob/main/docs/guides/secure-deployment.md Command to install the sandbox-runtime package using npm. ```bash npm install @anthropic-ai/sandbox-runtime ``` -------------------------------- ### Matcher Example Source: https://github.com/guess/claude_code/blob/main/docs/guides/hooks.md This example uses a matcher to run a hook only for file-modifying tools. ```elixir {:ok, session} = ClaudeCode.start_link( hooks: %{ PreToolUse: [ %{matcher: "Write|Edit", hooks: [MyApp.ValidateFilePath]} ] } ) ``` -------------------------------- ### Using a system-installed Claude CLI Source: https://github.com/guess/claude_code/blob/main/examples/README.md Configures the SDK to use an external 'claude' binary by setting 'cli_path' in config/dev.exs, then runs the examples. ```elixir import Config config :claude_code, cli_path: :global ``` ```bash mix run examples/streaming_example.exs mix run examples/character_streaming_example.exs ``` -------------------------------- ### SDK Example: Including user or project settings sources Source: https://github.com/guess/claude_code/blob/main/docs/guides/modifying-system-prompts.md Example of how to include user or project settings sources in the query for SDK users. ```elixir {:ok, result} = ClaudeCode.query("Review this module for issues", setting_sources: ["user"] ) ``` -------------------------------- ### Install CLI Source: https://github.com/guess/claude_code/blob/main/docs/guides/hosting.md Command to pre-install the CLI binary during a release build. ```bash mix claude_code.install ``` -------------------------------- ### Settings configuration example (file path) Source: https://github.com/guess/claude_code/blob/main/docs/guides/modifying-system-prompts.md Example of passing settings as a path to a JSON file using the :settings option. ```elixir {:ok, session} = ClaudeCode.start_link( settings: "/path/to/settings.json" ) ``` -------------------------------- ### Start as a named node Source: https://github.com/guess/claude_code/blob/main/docs/guides/distributed-sessions.md Example of starting the remote node with a name and cookie, both for direct execution and within a release. ```bash # Start the remote node with a name and cookie elixir --name claude@gpu-server --cookie my_secret -S mix run --no-halt ``` ```bash # rel/env.sh.eex export RELEASE_NODE="claude@$(hostname -f)" export RELEASE_COOKIE="my_secret" export ANTHROPIC_API_KEY="sk-ant-..." ``` -------------------------------- ### Minimal Stub Example Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Example of a minimal stub that works because ClaudeCode.Test automatically adds system and result messages. ```elixir # This minimal stub works - system and result are auto-added ClaudeCode.Test.stub(ClaudeCode, fn _, _ -> [ClaudeCode.Test.text("Hello")] end) ``` -------------------------------- ### Result Messages Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Examples of creating result messages. ```elixir # Default success result ClaudeCode.Test.result() # Custom result ClaudeCode.Test.result("Task completed successfully") # Error result ClaudeCode.Test.result("Rate limit exceeded", is_error: true) ``` -------------------------------- ### Text Messages Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Examples of creating text messages. ```elixir # Simple text response ClaudeCode.Test.text("Hello world!") # With options ClaudeCode.Test.text("Done", stop_reason: :end_turn) ``` -------------------------------- ### Start a new session with a specific agent Source: https://github.com/guess/claude_code/blob/main/docs/guides/subagents.md This example demonstrates how to start a new Claude Code session and pre-configure it with a specific agent named 'reviewer'. ```elixir {:ok, session} = ClaudeCode.start_link( agents: [ Agent.new( name: "reviewer", description: "Code reviewer", prompt: "You review code for quality." ) ], agent: "reviewer" ) ``` -------------------------------- ### Running the Checkpointing Example Source: https://github.com/guess/claude_code/blob/main/docs/guides/file-checkpointing.md Command to execute the interactive checkpointing script. ```bash elixir -S mix run try_checkpointing.exs ``` -------------------------------- ### Thinking Blocks Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Examples of creating thinking block messages. ```elixir # Extended thinking ClaudeCode.Test.thinking("Let me analyze step by step...") # Thinking followed by response ClaudeCode.Test.thinking("First I need to...", text: "Here's my answer") ``` -------------------------------- ### Tool Results Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Examples of creating tool result messages. ```elixir # Successful tool result (string) ClaudeCode.Test.tool_result("file contents here") # Structured data (maps are auto-encoded to JSON) ClaudeCode.Test.tool_result(%{status: "success", files: ["a.ex", "b.ex"]}) # Failed tool result ClaudeCode.Test.tool_result("Permission denied", is_error: true) ``` -------------------------------- ### Loading plugins with mixed formats Source: https://github.com/guess/claude_code/blob/main/docs/guides/plugins.md Example demonstrating that mixed formats (path strings and typed configuration maps) are accepted when loading plugins. ```elixir {:ok, session} = ClaudeCode.start_link( plugins: [ "./my-plugin", %{type: :local, path: "./another-plugin"} ] ) ``` -------------------------------- ### Accessing application state example Source: https://github.com/guess/claude_code/blob/main/docs/guides/custom-tools.md Example demonstrating how in-process tools can access application state like Ecto repositories and caches. ```elixir defmodule MyApp.Tools do use ClaudeCode.MCP.Server, name: "app-tools" tool :query_user do description "Look up a user by email" field :email, :string, required: true def execute(%{email: email}) do case MyApp.Repo.get_by(MyApp.User, email: email) do nil -> {:error, "User not found"} user -> {:ok, "#{user.name} (#{user.email})"} end end end tool :cache_stats do description "Get cache statistics" def execute(_params) do stats = MyApp.Cache.stats() {:ok, stats} end end end ``` -------------------------------- ### Dynamic Stubs Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Example of a dynamic stub that responds based on the query. ```elixir ClaudeCode.Test.stub(ClaudeCode, fn query, opts -> cond do String.contains?(query, "error") -> [ClaudeCode.Test.result("Something went wrong", is_error: true)] String.contains?(query, "file") -> [ ClaudeCode.Test.tool_use("Read", %{file_path: "/tmp/test.txt"}), ClaudeCode.Test.tool_result(%{content: "file contents", size: 123}), ClaudeCode.Test.text("I read the file"), ClaudeCode.Test.result() ] true -> [ClaudeCode.Test.text("Default response")] end end) ``` -------------------------------- ### Example of using allowed_tools with permission_mode: :dont_ask Source: https://github.com/guess/claude_code/blob/main/docs/guides/permissions.md This example demonstrates how to configure an agent to only approve specific tools and deny all others outright, without prompting. ```elixir {:ok, result} = ClaudeCode.query( "Analyze this codebase", allowed_tools: ["Read", "Glob", "Grep"], permission_mode: :dont_ask ) ``` -------------------------------- ### Register Stubs in Tests Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Example of registering a stub for a simple greeting test. ```elixir test "returns greeting" do ClaudeCode.Test.stub(ClaudeCode, fn _query, _opts -> [ ClaudeCode.Test.text("Hello! How can I help?") ] end) {:ok, session} = ClaudeCode.start_link() result = session |> ClaudeCode.stream("Hi") |> ClaudeCode.Stream.final_text() assert result == "Hello! How can I help?" end ``` -------------------------------- ### In-Process MCP Tools Configuration Source: https://github.com/guess/claude_code/blob/main/docs/guides/distributed-sessions.md Example of starting a session with in-process MCP servers. ```elixir {:ok, session} = ClaudeCode.start_link( cwd: "/workspaces/project", mcp_servers: %{"my-tools" => MyApp.Tools}, allowed_tools: ["mcp__my-tools__add"], adapter: {ClaudeCode.Adapter.Node, [node: :"claude@sandbox"]} ) ``` -------------------------------- ### Loading plugins with typed configuration maps Source: https://github.com/guess/claude_code/blob/main/docs/guides/plugins.md Example of loading plugins using typed configuration maps with `:type` and `:path` keys. ```elixir {:ok, session} = ClaudeCode.start_link( plugins: [ %{type: :local, path: "./my-plugin"}, %{type: :local, path: "/absolute/path/to/another-plugin"} ] ) ``` -------------------------------- ### Example of approving or denying tool use Source: https://github.com/guess/claude_code/blob/main/docs/guides/user-input.md This example asks Claude to create and delete a test file. When Claude attempts each operation, the hook prints the tool request to the terminal and prompts for y/n approval. ```elixir {:ok, session} = ClaudeCode.start_link( hooks: %{ PreToolUse: [ %{hooks: [fn %{tool_name: name, tool_input: input}, _tool_use_id -> IO.puts("\nTool: #{name}") if name == "Bash" do IO.puts("Command: #{input["command"]}") if input["description"], do: IO.puts("Description: #{input["description"]}") else IO.puts("Input: #{inspect(input)}") end case IO.gets("Allow this action? (y/n): ") |> String.trim() do "y" -> {:allow, updated_input: input} _ -> {:deny, message: "User denied this action"} end end]} ] } ) session |> ClaudeCode.stream("Create a test file in /tmp and then delete it") |> ClaudeCode.Stream.final_text() |> IO.puts() ``` -------------------------------- ### Code review command example Source: https://github.com/guess/claude_code/blob/main/docs/guides/slash-commands.md A practical example of a custom command for comprehensive code review, including allowed tools and bash command execution to get changed files. ```markdown --- allowed-tools: Read, Grep, Glob, Bash(git diff:*) description: Comprehensive code review --- ## Changed Files !`git diff --name-only HEAD~1` ``` -------------------------------- ### Testing Hook Handlers Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Example of testing a PostToolUse hook handler to ensure it receives events correctly. ```elixir test "PostToolUse hook receives events" do hook = fn %{tool_name: name}, _id -> send(self(), {:tool_executed, name}) :ok end ClaudeCode.Test.stub(ClaudeCode, fn _, _ -> [ ClaudeCode.Test.tool_use("Bash", %{command: "echo hi"}), ClaudeCode.Test.tool_result("hi"), ClaudeCode.Test.result() ] end) {:ok, session} = ClaudeCode.start_link( hooks: %{PostToolUse: [%{hooks: [hook]}]} ) session |> ClaudeCode.stream("run echo") |> Stream.run() assert_received {:tool_executed, "Bash"} end ``` -------------------------------- ### Complete Flow Example Source: https://github.com/guess/claude_code/blob/main/docs/guides/file-checkpointing.md This example demonstrates the complete flow of enabling file checkpointing, capturing a checkpoint UUID, and then rewinding files to that checkpoint. ```elixir alias ClaudeCode.Message.UserMessage # Steps 1-2: Enable checkpointing (env var is set automatically) {:ok, session} = ClaudeCode.start_link( enable_file_checkpointing: true, permission_mode: :accept_edits ) # Step 3: Run a query and capture the first user message UUID as a checkpoint checkpoint_id = session |> ClaudeCode.stream("Refactor the authentication module") |> Enum.reduce(nil, fn %UserMessage{uuid: uuid}, nil when not is_nil(uuid) -> uuid _, cp -> cp end) # Step 4: Rewind files to the checkpoint {:ok, _} = ClaudeCode.Session.rewind_files(session, checkpoint_id) ``` -------------------------------- ### Loading plugins with path strings Source: https://github.com/guess/claude_code/blob/main/docs/guides/plugins.md Example of loading plugins by providing their local file system paths as simple strings in the options configuration. ```elixir {:ok, session} = ClaudeCode.start_link( plugins: ["./my-plugin", "/absolute/path/to/another-plugin"] ) ``` -------------------------------- ### Single sandbox server, multiple tenants Source: https://github.com/guess/claude_code/blob/main/docs/guides/distributed-sessions.md Example of starting multiple tenant sessions on a single sandbox server. ```elixir defmodule MyApp.Claude do @sandbox_node :"claude@sandbox-server" def start_session(tenant_id, opts \\ []) do opts = Keyword.merge([ cwd: "/workspaces/#{tenant_id}", permission_mode: :dont_ask, allowed_tools: ["Read", "Edit", "Write", "Glob", "Grep", "Bash"], adapter: {ClaudeCode.Adapter.Node, [node: @sandbox_node]} ], opts) ClaudeCode.start_link(opts) end end # Each tenant gets a separate session — lightweight on your app server, # CLI resources consumed on the sandbox server {:ok, session_a} = MyApp.Claude.start_session("tenant-a") {:ok, session_b} = MyApp.Claude.start_session("tenant-b") ``` -------------------------------- ### Manual Session Supervision Setup Source: https://github.com/guess/claude_code/blob/main/docs/reference/troubleshooting.md Example of how to set up manual supervision for a ClaudeCode session GenServer. ```elixir # ClaudeCode doesn't provide built-in child_spec # You need to create a wrapper or use a simple supervisor defmodule MyApp.ClaudeSupervisor do use Supervisor def start_link(opts) do Supervisor.start_link(__MODULE__, opts, name: __MODULE__) end def init(opts) do children = [ {ClaudeCode, [api_key: "...", name: :claude_session]} ] Supervisor.init(children, strategy: :one_for_one) end end ``` -------------------------------- ### Using CLAUDE.md with the SDK Source: https://github.com/guess/claude_code/blob/main/docs/guides/modifying-system-prompts.md Example of how to use CLAUDE.md with the Agent SDK by specifying setting_sources. ```elixir # You must specify setting_sources to load CLAUDE.md {:ok, result} = ClaudeCode.query("Add a new GenServer module for user sessions", setting_sources: ["project"] ) ``` -------------------------------- ### Ephemeral Sessions with ClaudeCode.start_link/1 Source: https://github.com/guess/claude_code/blob/main/docs/guides/hosting.md Example of using `ClaudeCode.start_link/1` with explicit lifecycle management for ephemeral sessions. ```elixir defmodule MyApp.Agent do def run(prompt, opts \ []) do {:ok, session} = ClaudeCode.start_link(opts) try do session |> ClaudeCode.stream(prompt) |> ClaudeCode.Stream.collect() after ClaudeCode.stop(session) end end end ``` -------------------------------- ### Per-user sessions in Phoenix LiveView Source: https://github.com/guess/claude_code/blob/main/docs/guides/distributed-sessions.md Example of starting a remote Claude session within a Phoenix LiveView and streaming responses. ```elixir defmodule MyAppWeb.ChatLive do use MyAppWeb, :live_view def mount(_params, %{"user_id" => user_id}, socket) do {:ok, session} = ClaudeCode.start_link( cwd: "/workspaces/#{user_id}", model: "claude-sonnet-4-20250514", permission_mode: :dont_ask, include_partial_messages: true, adapter: {ClaudeCode.Adapter.Node, [node: :"claude@sandbox"]} ) {:ok, assign(socket, claude: session, response: "", streaming: false)} end def handle_event("send", %{"message" => msg}, socket) do if socket.assigns.streaming do {:noreply, socket} else lv = self() Task.Supervisor.start_child(MyApp.TaskSupervisor, fn -> try do socket.assigns.claude |> ClaudeCode.stream(msg) |> ClaudeCode.Stream.text_deltas() |> Enum.each(&send(lv, {:chunk, &1})) send(lv, :stream_done) catch kind, reason -> send(lv, {:stream_error, {kind, reason}}) end end) {:noreply, assign(socket, response: "", streaming: true)} end end def handle_info({:chunk, chunk}, socket) do {:noreply, assign(socket, response: socket.assigns.response <> chunk)} end def handle_info(:stream_done, socket) do {:noreply, assign(socket, streaming: false)} end def handle_info({:stream_error, _reason}, socket) do {:noreply, assign(socket, streaming: false)} end end ``` -------------------------------- ### Elixir Implementation Example Source: https://github.com/guess/claude_code/blob/main/docs/guides/user-input.md An Elixir module demonstrating how to handle the 'AskUserQuestion' tool, display questions to the user, collect input, parse responses (including free-text), and return answers to Claude. ```elixir defmodule MyApp.UserInput do @behaviour ClaudeCode.Hook @impl true def call(%{tool_name: "AskUserQuestion", tool_input: input}, _tool_use_id) do handle_questions(input) end def call(%{tool_input: input}, _tool_use_id) do # Auto-approve other tools for this example {:allow, updated_input: input} end defp handle_questions(input) do questions = input["questions"] || [] answers = Map.new(questions, fn q -> IO.puts("\n#{q["header"]}: #{q["question"]}") options = q["options"] || [] Enum.with_index(options, 1) |> Enum.each(fn {opt, i} -> IO.puts(" #{i}. #{opt["label"]} - #{opt["description"]}") end) if q["multiSelect"] do IO.puts(" (Enter numbers separated by commas, or type your own answer)") else IO.puts(" (Enter a number, or type your own answer)") end response = IO.gets("Your choice: ") |> String.trim() {q["question"], parse_response(response, options)} end) {:allow, updated_input: %{"questions" => questions, "answers" => answers}} end defp parse_response(response, options) do indices = response |> String.split(",") |> Enum.map(&String.trim/1) |> Enum.map(&Integer.parse/1) |> Enum.filter(&match?({_, ""}, &1)) |> Enum.map(fn {n, _} -> n - 1 end) |> Enum.filter(&(&1 >= 0 and &1 < length(options))) case indices do [] -> response _ -> indices |> Enum.map(&Enum.at(options, &1)["label"]) |> Enum.join(", ") end end end {:ok, session} = ClaudeCode.start_link( hooks: %{ PreToolUse: [MyApp.UserInput] } ) session |> ClaudeCode.stream("Help me decide on the tech stack for a new mobile app") |> ClaudeCode.Stream.final_text() |> IO.puts() ``` -------------------------------- ### Listing marketplaces Source: https://github.com/guess/claude_code/blob/main/docs/guides/plugins.md Example of listing configured plugin marketplaces. ```elixir {:ok, marketplaces} = ClaudeCode.Plugin.Marketplace.list() Enum.each(marketplaces, fn m -> IO.puts("#{m.name} (#{m.source}: #{m.repo})") end) ``` -------------------------------- ### Testing Stream Processing Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Example showing how to test if streaming text is processed correctly by stubbing multiple text messages. ```elixir test "processes streaming text correctly" do ClaudeCode.Test.stub(ClaudeCode, fn _, _ -> [ ClaudeCode.Test.text("Part 1"), ClaudeCode.Test.text("Part 2"), ClaudeCode.Test.text("Part 3") ] end) {:ok, session} = ClaudeCode.start_link() texts = session |> ClaudeCode.stream("test") |> ClaudeCode.Stream.text_content() |> Enum.to_list() assert texts == ["Part 1", "Part 2", "Part 3"] end ``` -------------------------------- ### Shared Mode Source: https://github.com/guess/claude_code/blob/main/docs/reference/testing.md Example of setting ClaudeCode testing to shared mode, where all processes can access stubs without explicit allowances. ```elixir setup do ClaudeCode.Test.set_mode_to_shared() :ok end ``` -------------------------------- ### CLI not found on remote node error handling Source: https://github.com/guess/claude_code/blob/main/docs/guides/distributed-sessions.md Example of handling the error when the Claude CLI binary is not installed on the remote node. ```elixir case ClaudeCode.start_link( cwd: "/workspaces/test", adapter: {ClaudeCode.Adapter.Node, [node: :"claude@gpu-server"]} ) do {:ok, session} -> session {:error, {:cli_not_found, message}} -> IO.puts(message) end ``` -------------------------------- ### Distributed Sessions Example Source: https://github.com/guess/claude_code/blob/main/README.md Starts a session connected to a remote Node.js CLI process via Erlang distribution. ```elixir {:ok, session} = ClaudeCode.start_link( cwd: "/workspaces/#{tenant_id}", adapter: {ClaudeCode.Adapter.Node, [node: :"claude@sandbox-server"]} ) # Same API — streaming, tools, hooks, resumption all work unchanged session |> ClaudeCode.stream("Analyze the codebase") |> ClaudeCode.Stream.text_content() |> Enum.each(&IO.write/1) ```