# Managed Agents — Ruby > **Bindings not shown here:** This README covers the most common managed-agents flows for Ruby. If you need a class, method, namespace, field, or behavior that isn't shown, WebFetch the Ruby SDK repo **or the relevant docs page** from `shared/live-sources.md` rather than guess. Do not extrapolate from cURL shapes or another language's SDK. > **Agents are persistent — create once, reference by ID.** Store the agent ID returned by `client.beta.agents.create` and pass it to every subsequent `client.beta.sessions.create`; do not call `agents.create` in the request path. The Anthropic CLI is one convenient way to create agents and environments from version-controlled YAML — its URL is in `shared/live-sources.md`. The examples below show in-code creation for completeness; in production the create call belongs in setup, not in the request path. ## Installation ```bash gem install anthropic ``` ## Client Initialization ```ruby require "anthropic" # Default (uses ANTHROPIC_API_KEY env var) client = Anthropic::Client.new # Explicit API key client = Anthropic::Client.new(api_key: "your-api-key") ``` > ⚠️ **Trailing underscores:** The Ruby SDK uses `system_:` and `send_(` (trailing underscore) to avoid shadowing `Kernel#system` and `Kernel#send`. Use these forms throughout managed-agents code. --- ## Create an Environment ```ruby environment = client.beta.environments.create( name: "my-dev-env", config: { type: "cloud", networking: {type: "unrestricted"} } ) puts "Environment ID: #{environment.id}" # env_... ``` --- ## Create an Agent (required first step) > ⚠️ **There is no inline agent config.** `model`/`system_`/`tools` live on the agent object, not the session. Always start with `client.beta.agents.create()` — the session takes either `agent: agent.id` or the typed hash form `agent: {type: "agent", id: agent.id, version: agent.version}`. ### Minimal ```ruby # 1. Create the agent (reusable, versioned) agent = client.beta.agents.create( name: "Coding Assistant", model: :"{{OPUS_ID}}", system_: "You are a helpful coding assistant.", tools: [{type: "agent_toolset_20260401"}] ) # 2. Start a session session = client.beta.sessions.create( agent: {type: "agent", id: agent.id, version: agent.version}, environment_id: environment.id, title: "Quickstart session" ) puts "Session ID: #{session.id}" ``` ### Updating an Agent Updates create new versions; the agent object is immutable per version. ```ruby updated_agent = client.beta.agents.update( agent.id, version: agent.version, system_: "You are a helpful coding agent. Always write tests." ) puts "New version: #{updated_agent.version}" # List all versions client.beta.agents.versions.list(agent.id).auto_paging_each do |version| puts "Version #{version.version}: #{version.updated_at.iso8601}" end # Archive the agent archived = client.beta.agents.archive(agent.id) puts "Archived at: #{archived.archived_at.iso8601}" ``` --- ## Send a User Message ```ruby client.beta.sessions.events.send_( session.id, events: [{ type: "user.message", content: [{type: "text", text: "Review the auth module"}] }] ) ``` > 💡 **Stream-first:** Open the stream *before* (or concurrently with) sending the message. The stream only delivers events that occur after it opens — stream-after-send means early events arrive buffered in one batch. See [Steering Patterns](../../shared/managed-agents-events.md#steering-patterns). --- ## Stream Events (SSE) ```ruby # Open the stream first, then send the user message stream = client.beta.sessions.events.stream_events(session.id) client.beta.sessions.events.send_( session.id, events: [{ type: "user.message", content: [{type: "text", text: "Summarize the repo README"}] }] ) stream.each do |event| case event.type in :"agent.message" event.content.each { |block| print block.text } in :"agent.tool_use" puts "\ [Using tool: #{event.name}]" in :"session.status_idle" break in :"session.error" puts "\ [Error: #{event.error&.message || "unknown"}]" break else # ignore other event types end end ``` > ℹ️ Event `.type` is a Symbol (compare with `:"agent.message"`, not `"agent.message"`). ### Reconnecting and Tailing When reconnecting mid-session, list past events first to dedupe, then tail live events: ```ruby require "set" stream = client.beta.sessions.events.stream_events(session.id) # Stream is open and buffering. List history before tailing live. seen_event_ids = Set.new client.beta.sessions.events.list(session.id).auto_paging_each { |past| seen_event_ids << past.id } # Tail live events, skipping anything already seen stream.each do |event| next if seen_event_ids.include?(event.id) seen_event_ids << event.id case event.type in :"agent.message" event.content.each { |block| print block.text } in :"session.status_idle" break else # ignore other event types end end ``` --- ## Provide Custom Tool Result > ℹ️ The Ruby managed-agents bindings for `user.custom_tool_result` are not yet documented in this skill or in the apps source examples. Refer to `shared/managed-agents-events.md` for the wire format and the `anthropic` Ruby gem repository for the corresponding params. --- ## Poll Events ```ruby client.beta.sessions.events.list(session.id).auto_paging_each do |event| puts "#{event.type}: #{event.id}" end ``` --- ## Upload a File ```ruby require "pathname" file = client.beta.files.upload(file: Pathname("data.csv")) puts "File ID: #{file.id}" # Mount in a session session = client.beta.sessions.create( agent: agent.id, environment_id: environment.id, resources: [ { type: "file", file_id: file.id, mount_path: "/workspace/data.csv" } ] ) ``` ### Add and Manage Resources on an Existing Session ```ruby # Attach an additional file to an open session resource = client.beta.sessions.resources.add( session.id, type: "file", file_id: file.id ) puts resource.id # "sesrsc_01ABC..." # List resources on the session listed = client.beta.sessions.resources.list(session.id) listed.data.each { |entry| puts "#{entry.id} #{entry.type}" } # Detach a resource client.beta.sessions.resources.delete(resource.id, session_id: session.id) ``` --- ## List and Download Session Files ```ruby files = client.beta.files.list(scope_id: "sesn_abc123", betas: ["managed-agents-2026-04-01"]) content = client.beta.files.download(files.data[0].id) File.binwrite("output.txt", content.read) ``` --- ## Session Management ```ruby # List environments environments = client.beta.environments.list # Retrieve a specific environment env = client.beta.environments.retrieve(environment.id) # Archive an environment (read-only, existing sessions continue) client.beta.environments.archive(environment.id) # Delete an environment (only if no sessions reference it) client.beta.environments.delete(environment.id) # Delete a session client.beta.sessions.delete(session.id) ``` --- ## MCP Server Integration ```ruby # Agent declares MCP server (no auth here — auth goes in a vault) agent = client.beta.agents.create( name: "GitHub Assistant", model: :"{{OPUS_ID}}", mcp_servers: [ { type: "url", name: "github", url: "https://api.githubcopilot.com/mcp/" } ], tools: [ {type: "agent_toolset_20260401"}, {type: "mcp_toolset", mcp_server_name: "github"} ] ) # Session attaches vault(s) containing credentials for those MCP server URLs session = client.beta.sessions.create( agent: {type: "agent", id: agent.id, version: agent.version}, environment_id: environment.id, vault_ids: [vault.id] ) ``` See `shared/managed-agents-tools.md` §Vaults for creating vaults and adding credentials. --- ## Vaults ```ruby # Create a vault vault = client.beta.vaults.create( display_name: "Alice", metadata: {external_user_id: "usr_abc123"} ) puts vault.id # "vlt_01ABC..." # Add an OAuth credential credential = client.beta.vaults.credentials.create( vault.id, display_name: "Alice's Slack", auth: { type: "mcp_oauth", mcp_server_url: "https://mcp.slack.com/mcp", access_token: "xoxp-...", expires_at: "2026-04-15T00:00:00Z", refresh: { token_endpoint: "https://slack.com/api/oauth.v2.access", client_id: "1234567890.0987654321", scope: "channels:read chat:write", refresh_token: "xoxe-1-...", token_endpoint_auth: { type: "client_secret_post", client_secret: "abc123..." } } } ) # Rotate the credential (e.g., after a token refresh) client.beta.vaults.credentials.update( credential.id, vault_id: vault.id, auth: { type: "mcp_oauth", access_token: "xoxp-new-...", expires_at: "2026-05-15T00:00:00Z", refresh: {refresh_token: "xoxe-1-new-..."} } ) # Archive a vault client.beta.vaults.archive(vault.id) ``` --- ## GitHub Repository Integration Mount a GitHub repository as a session resource (a vault holds the GitHub MCP credential): ```ruby session = client.beta.sessions.create( agent: agent.id, environment_id: environment.id, vault_ids: [vault.id], resources: [ { type: "github_repository", url: "https://github.com/org/repo", mount_path: "/workspace/repo", authorization_token: "ghp_your_github_token" } ] ) ``` Multiple repositories on the same session: ```ruby resources = [ { type: "github_repository", url: "https://github.com/org/frontend", mount_path: "/workspace/frontend", authorization_token: "ghp_your_github_token" }, { type: "github_repository", url: "https://github.com/org/backend", mount_path: "/workspace/backend", authorization_token: "ghp_your_github_token" } ] ``` Rotating a repository's authorization token: ```ruby listed = client.beta.sessions.resources.list(session.id) repo_resource_id = listed.data.first.id client.beta.sessions.resources.update( repo_resource_id, session_id: session.id, authorization_token: "ghp_your_new_github_token" ) ```