Core Concepts

Start with an Agent: a Ruby class that gives a model instructions and operations it can call. This guide builds on the help center example in Getting Started, including its HelpCenterLookupTool and provider setup.

class CustomerSupportAgent < LittleGhost::Agent
  model "openrouter:openai/gpt-5.6-luna"
  system_prompt "Answer customer questions clearly."
  tools HelpCenterLookupTool
end

run = CustomerSupportAgent.ask("What is the refund policy?")
run.response

From there, add only what the work needs. Give the agent a tool. Let it ask a specialist for help. Or coordinate several agents while the rest of your application keeps making the same call.

An Agent carries a request through to an answer

An Agent defines one model-driven behavior. It chooses the model, supplies the instructions and tools, and carries one request through to an answer.

The model can answer immediately or ask to call a Tool. LittleGhost runs the Tool and sends its result back to the model, which can continue working. That back-and-forth is the model loop.

The class holds the behavior you want to reuse. Each call brings its own input, history, context, settings, and attachments. Request data never needs to live on the class.

CustomerSupportAgent
├── model selection
├── system prompt
├── HelpCenterLookupTool
└── limits and optional capabilities

An Agent can return text or checked, structured data. You can add streaming, saved conversations, or callbacks later. None of them are required to begin.

A Tool connects the model to Ruby

A Tool is one focused thing an agent can ask your application to do. It has a name, a description, an input schema, and the Ruby code that does the work.

class HelpCenterLookupTool < LittleGhost::Tool
  description "Look up a help center entry by topic."
  input_schema(
    type: "object",
    properties: {topic: {type: "string"}},
    required: ["topic"],
    additionalProperties: false
  )

  def call(input)
    {"refunds" => "Refunds are available within 30 days."}
      .fetch(input.fetch("topic"))
  end
end

LittleGhost checks the model’s arguments, calls the Tool, and gives the result back to the model. The schema checks shape, not permission. Check permission inside the Tool using identity and account information from your application.

Tools follows that path from model input to application code, including run-scoped bindings, concurrency, retries, and sandbox delegation.

A Run records one request

Every .ask or .stream_ask creates a Run. Think of it as the record of one trip through LittleGhost. It opens what the request needs, records how the work ended, and closes the resources it owns.

run = CustomerSupportAgent.ask("What is the refund policy?")

run.completed? # => true
run.response
# One possible response: Refunds are available within 30 days.
run.usage      # Token counts reported by the model provider.
run.result     # => the complete LittleGhost::RunResult

The Agent defines reusable behavior; the Run records what happened this time.

The final RunResult, available through run.result, holds the answer and details such as token usage. Its output returns text unless you configured the Agent to return checked data, such as a hash of named fields. See Structured Results and Content for that alternative. Use run.response when you want the text answer.

When a Tool needs to know who is asking, pass information from your application with the request. Tools explains how it reaches the Tool. When a conversation should continue across requests, a Session saves its history and working state; Running in Production covers that setup.

An Assembly can look like one Agent

One model loop is not always enough. LittleGhost calls any unit that a caller can invoke like an Agent an Assembly.

An Agent is the smallest Assembly. Workflow, Swarm, and Graph coordinate several participants while preserving the same entrypoints:

CustomerSupportAgent.ask(question)
ResponseWorkflow.ask(question)
ProblemSolverSwarm.ask(question)
SupportFlowGraph.ask(question)

That shared calling style is what makes composition feel natural. A controller, job, or CLI does not need to know whether one Agent answered or a whole support process worked together.

Choose who controls the next step

The coordination types differ mainly in who decides what happens next:

Need Choose Who controls the next step?
One model-driven behavior Agent The active model loop
A model should delegate a named task Subagent The parent model
Ruby should enforce ordering or branching Workflow The workflow’s Ruby code
Specialists should choose permitted handoffs Swarm The active agent
Allowed routes should be visible in advance Graph Declared nodes and edges

Subagents bring in a specialist

A subagent is a specialist that a parent Agent can call for help. The parent model chooses when to delegate, reads the result, and then continues its own answer.

The examples below omit the specialist Agent definitions. Each is an Agent class like CustomerSupportAgent, with instructions and tools suited to its task. Compose Agents expands on these coordination patterns.

class CustomerSupportAgent < LittleGhost::Agent
  model "openrouter:openai/gpt-5.6-luna"
  subagent ResearchAgent, kind: "research"
end

Use a subagent when delegation is part of one model’s decision-making. Use a Workflow when application code must guarantee that a step happens.

Workflows make Ruby the coordinator

A Workflow coordinates work with ordinary Ruby. Its perform method can call an Agent or another Assembly, read a result, choose a branch, or run independent steps together.

invoke prepares a participant’s call without running it yet. Read .output to run it and use its answer in Ruby. Return the final invoke call to use that participant’s answer as the Workflow’s result.

class ResponseWorkflow < LittleGhost::Workflow
  private

  def perform
    research = invoke(ResearchAgent).output
    invoke CustomerSupportAgent, input: <<~PROMPT
      #{input.text}

      Research:
      #{research}
    PROMPT
  end
end

In this example, research finishes before the support Agent begins. input.text is the original question; the Workflow adds the research to it.

You can also inspect an answer before choosing it as the final result, without running the participant again. Compose Agents shows how, along with ways to display each participant’s progress.

Workflow children receive the caller’s history and application context by default. Pass history: [], context: {}, or redacted values when a participant should receive less.

Swarms let agents hand work to one another

A Swarm is a group of Agents that can hand work to one another. One member is active at a time. It can answer the caller or choose one of its allowed specialists.

class ProblemSolverSwarm < LittleGhost::Swarm
  member TriageAgent
  member BillingAgent
  member AccountAgent

  start TriageAgent
  handoff TriageAgent, to: [BillingAgent, AccountAgent]
end

A Swarm is intentionally agent-to-agent. Its members are Agents, not other kinds of Assembly. Caller history and application context stay hidden unless a member opts in. A handoff message comes from another model, so a receiving Agent should use it as context rather than proof that an action is permitted.

Graphs make routes visible

A Graph lays out the steps and routes through a task. Each named node runs an Agent or another Assembly. An edge says which node can run next.

class SupportFlowGraph < LittleGhost::Graph
  node :triage, TriageAgent
  node :billing, BillingAgent
  node :general, CustomerSupportAgent
  node :respond, CustomerSupportAgent

  start :triage
  edge :triage, :billing do |state|
    state.result(:triage).output == "billing"
  end
  edge :triage, :general
  edge :billing, :respond
  edge :general, :respond
  finish :respond
end

Here, TriageAgent is expected to answer billing for billing questions. That answer selects the conditional billing route. Otherwise, the unconditional general route is the fallback; it does not run alongside the billing route.

Graph nodes receive the original task and results from the nodes immediately before them. They do not receive caller history or application context unless their declarations opt in. Compose Agents explains parallel routes, joins, input mapping, and data boundaries.

One result, even when several agents help

Every assembly produces the same top-level Run and final RunResult. Composite assemblies also keep a size-limited record of the participants that ran:

run = SupportFlowGraph.ask("Why was I charged twice?")

run.response
run.result.steps
run.result.trajectory.transitions

This record shows which participants ran. Compose Agents explains builders, detailed routing records, and live events from nested Agents.

Handle the outcome

An Agent or coordinated Assembly normally returns a Run even when the work fails. Check its outcome before using the answer:

What happened Run outcome What to inspect
Work completed completed run.response or run.result
Model, provider, or assembly execution failed failed run.error
The deadline stopped work partial Any response produced so far
Cancellation stopped work cancelled No response is returned

A Tool error need not end the Run: LittleGhost can give the model a safe error result so it can try again. Unexpected exception messages stay in application diagnostics rather than going to the model.

Some failures raise Ruby exceptions instead of returning a Run, including invalid setup before work starts and failures while closing resources or delivering events. Running in Production covers error handling and shutdown; Run lists the streaming events for each outcome.

The pieces now fit together: Agents define behavior. Tools connect them to Ruby. Runs record one execution. Assemblies let the system grow without changing the caller.

Continue with Models and Providers to choose model targets and configure provider connections. When you need several agents to work together, Compose Agents builds on the same concepts.