little_ghost 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +72 -74
  3. data/docs/guides/assemblies.md +286 -0
  4. data/docs/guides/core_concepts.md +159 -135
  5. data/docs/guides/getting_started.md +114 -83
  6. data/docs/guides/production.md +187 -0
  7. data/docs/guides/prompt_views.md +132 -0
  8. data/lib/little_ghost/ag_ui/adapter.rb +3 -3
  9. data/lib/little_ghost/agent/delegation.rb +35 -8
  10. data/lib/little_ghost/agent/tool_loop.rb +2 -1
  11. data/lib/little_ghost/agent.rb +280 -326
  12. data/lib/little_ghost/agent_builder.rb +20 -4
  13. data/lib/little_ghost/agent_factory.rb +3 -0
  14. data/lib/little_ghost/{agent_interruptions.rb → agent_interjections.rb} +12 -12
  15. data/lib/little_ghost/assembly.rb +345 -0
  16. data/lib/little_ghost/assembly_builder.rb +497 -0
  17. data/lib/little_ghost/assembly_execution.rb +535 -0
  18. data/lib/little_ghost/configuration.rb +263 -39
  19. data/lib/little_ghost/content.rb +5 -5
  20. data/lib/little_ghost/data_map.rb +209 -0
  21. data/lib/little_ghost/errors.rb +10 -2
  22. data/lib/little_ghost/execution.rb +206 -0
  23. data/lib/little_ghost/graph.rb +930 -0
  24. data/lib/little_ghost/message.rb +4 -4
  25. data/lib/little_ghost/model_resolver.rb +2 -2
  26. data/lib/little_ghost/prompt_resolver.rb +2 -0
  27. data/lib/little_ghost/run.rb +190 -64
  28. data/lib/little_ghost/run_context.rb +33 -20
  29. data/lib/little_ghost/run_result.rb +22 -11
  30. data/lib/little_ghost/runtime/hook.rb +9 -4
  31. data/lib/little_ghost/runtime.rb +134 -36
  32. data/lib/little_ghost/sandbox.rb +1 -1
  33. data/lib/little_ghost/session.rb +12 -23
  34. data/lib/little_ghost/session_store.rb +9 -5
  35. data/lib/little_ghost/session_stores/agent_core_memory.rb +64 -56
  36. data/lib/little_ghost/session_stores/filesystem.rb +261 -0
  37. data/lib/little_ghost/session_stores/memory.rb +7 -0
  38. data/lib/little_ghost/subagents/manager.rb +42 -42
  39. data/lib/little_ghost/support/executor.rb +14 -2
  40. data/lib/little_ghost/support/loader.rb +2 -2
  41. data/lib/little_ghost/support.rb +15 -3
  42. data/lib/little_ghost/swarm.rb +439 -0
  43. data/lib/little_ghost/tool.rb +88 -20
  44. data/lib/little_ghost/tools/write_todos.rb +6 -1
  45. data/lib/little_ghost/tracing/open_telemetry.rb +14 -3
  46. data/lib/little_ghost/unrestricted_sandbox.rb +1 -1
  47. data/lib/little_ghost/version.rb +1 -1
  48. data/lib/little_ghost/workflow.rb +224 -90
  49. data/lib/little_ghost.rb +36 -25
  50. metadata +17 -5
@@ -1,148 +1,156 @@
1
1
  # Core Concepts
2
2
 
3
- LittleGhost gives Ruby software two ways to compose AI behavior. Agents can choose among validated tools and delegated specialists, while agentic workflows keep required ordering and branching under application control. The customer support example makes that boundary visible: ModelResolver chooses provider-backed models, CustomerSupportAgent owns behavior, HelpCenterLookupTool exposes a narrow help center lookup, ResearchAgent handles delegated investigation, and ResponseWorkflow imposes a deterministic sequence when the surrounding system requires one.
4
-
5
- ```text
6
- shared configuration
7
- └── ModelResolver ── resolves model selections ──> provider clients
8
-
9
- one request
10
- └── Run
11
- ├── CustomerSupportAgent
12
- │ ├── HelpCenterLookupTool
13
- │ └── ResearchAgent subagent (model-directed)
14
- └── sessions, resources, usage, events, and terminal result
15
-
16
- one deterministic request
17
- └── Run ──> ResponseWorkflow ──> ResearchAgent ──> CustomerSupportAgent
18
- ```
19
-
20
- ## Models can be selected directly or by role
21
-
22
- An agent can name a canonical target directly when the choice belongs beside its behavior:
3
+ Build one model-driven behavior in a Ruby class, then call it like Ruby. That is the idea LittleGhost grows from.
23
4
 
24
5
  ```ruby
25
6
  class CustomerSupportAgent < LittleGhost::Agent
26
- model "openai:gpt-5.6-luna"
7
+ model "openrouter:openai/gpt-5.6-luna"
8
+ system_prompt "Answer customer questions clearly."
9
+ tools HelpCenterLookupTool
27
10
  end
11
+
12
+ run = CustomerSupportAgent.ask("Where is my order?")
13
+ run.response
28
14
  ```
29
15
 
30
- It can also attach trusted model settings without defining a shared profile:
16
+ 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.
31
17
 
32
- ```ruby
33
- class DeliberateSupportAgent < LittleGhost::Agent
34
- model(provider: "openai", model: "gpt-5.6-luna", reasoning_effort: "high")
35
- end
18
+ ## An Agent owns one model loop
19
+
20
+ An **Agent** defines one model-driven behavior. It chooses the model, supplies the instructions and tools, and carries one request through to an answer.
21
+
22
+ 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.
23
+
24
+ ```text
25
+ CustomerSupportAgent
26
+ ├── model selection
27
+ ├── system prompt
28
+ ├── HelpCenterLookupTool
29
+ └── limits and optional capabilities
36
30
  ```
37
31
 
38
- In both forms, `provider` is the name of a configured connection. A role such as `customer_support` adds stable application vocabulary when several agents or deployments should share routing policy:
32
+ An Agent can return text or checked, structured data. Later, you can add streaming, sessions, or callbacks. None of them are required to begin.
33
+
34
+ ## A Tool connects the model to Ruby
35
+
36
+ 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.
39
37
 
40
38
  ```ruby
41
- LittleGhost.configure do |config|
42
- config.providers = {
43
- openai: {adapter: :openai, api_key: ENV.fetch("OPENAI_API_KEY")}
44
- }
45
- config.models = {
46
- customer_support: {target: "openai:gpt-5.6-luna"}
47
- }
39
+ class HelpCenterLookupTool < LittleGhost::Tool
40
+ description "Look up a help center entry by topic."
41
+ input_schema(
42
+ type: "object",
43
+ properties: {topic: {type: "string"}},
44
+ required: ["topic"],
45
+ additionalProperties: false
46
+ )
47
+
48
+ def call(input)
49
+ {"refunds" => "Refunds are available within 30 days."}
50
+ .fetch(input.fetch("topic"))
51
+ end
48
52
  end
49
53
  ```
50
54
 
55
+ LittleGhost checks the model's arguments, calls the tool, and gives the result back to the model. The schema checks shape, not permission. Authorize sensitive reads and actions inside the tool with trusted application context.
56
+
57
+ ## A Run owns one top-level execution
58
+
59
+ 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.
60
+
51
61
  ```ruby
52
- class CustomerSupportAgent < LittleGhost::Agent
53
- model :customer_support
54
- end
62
+ run = CustomerSupportAgent.ask("Where is order 481?")
63
+
64
+ run.completed? # => true
65
+ run.response
66
+ # One possible response: Order 481 is out for delivery.
67
+ run.usage # => normalized token usage
68
+ run.result # => the complete LittleGhost::RunResult
55
69
  ```
56
70
 
57
- Strings and symbols without a colon are roles; strings containing a colon are canonical targets; mappings require `provider` and `model`, with remaining keys treated as model settings. Role names cannot contain a colon. Direct targets and mappings bypass role inheritance and overlays.
71
+ The Agent defines reusable behavior; the Run records what happened this time.
58
72
 
59
- Dotted roles inherit from the nearest registered parent. `ResearchAgent` can request `customer_support.research` and initially use the `customer_support` profile; registering `customer_support.research` later specializes it. A resolver caller may pass an explicit `profiles:` overlay without mutating the configured profiles or agent class. Because an overlay can select a different registered provider, model, and settings, it is trusted application configuration and must be constructed or allowlisted by the application rather than copied from unchecked request data. The base resolver does not inspect application-specific invocation fields.
73
+ ### Follow one request
60
74
 
61
- The provider performs model I/O. `LittleGhost::ModelResolver` resolves application intent into a `LittleGhost::Model`, which carries the provider, target, settings, details, and role for a run.
75
+ One Run owns the trip from request to result:
62
76
 
63
- ## Agents declare behavior
77
+ ```text
78
+ Run
79
+ ├── Invocation: caller input, history, and application context
80
+ ├── RunContext: mutable working state for this execution
81
+ └── Agent and Tools ──> RunResult
82
+ ```
64
83
 
65
- An agent class declares application behavior:
84
+ An **Invocation** is the request in LittleGhost's standard shape. Its `context` contains current request values supplied by your application. A Tool can read those values through `run.invocation.context` when it authorizes work.
66
85
 
67
- ```ruby
68
- class CustomerSupportAgent < LittleGhost::Agent
69
- description "Answers customer support questions."
70
- model "customer_support"
71
- system_prompt "Answer clearly. Check the help center before stating company guidance."
72
- tools HelpCenterLookupTool
73
- subagent ResearchAgent, kind: "research"
74
- end
75
- ```
86
+ The **RunContext** carries mutable working state in `context.state`. At the top level, saved Session state is loaded first, then current Invocation context is added. Child Assemblies may receive a copy, a mapped value, or no context at all. Recheck saved values before using them for permission decisions.
76
87
 
77
- The class-level DSL is inheritable. It can declare prompts, limits, callbacks, tool classes, structured results, context management, skills, and delegation. A capability mixin may be included in `LittleGhost::Agent`, but its behavior remains inactive until the corresponding DSL is called.
88
+ A Tool's **Binding** gives the Tool access to objects created for this run, including the Agent, Run, workspace, and sandbox. These objects are separate from the arguments chosen by the model.
78
89
 
79
- `CustomerSupportAgent.ask` creates a standalone entrypoint, builds and consumes a `LittleGhost::Run`, and returns that run. `CustomerSupportAgent.stream_ask` creates the same kind of entrypoint and yields the run's events. Create `CustomerSupportAgent.new(runtime:)` explicitly when several calls should reuse one runtime. Agents built by a runtime are instead scoped to their owning run and return a `LittleGhost::RunResult` from `#call`.
90
+ The final **RunResult** keeps the complete assembly result. Its `text` is the final text answer. Its `output` returns structured data when the Agent declared a result schema, and text otherwise. The top-level `Run#response` is always the caller-facing text.
80
91
 
81
- That distinction explains two useful return paths:
92
+ ### See how a call ended
82
93
 
83
- ```ruby
84
- run = CustomerSupportAgent.ask("Can I get a refund?")
85
- run.response # final text from the top-level execution
86
- run.result.output # text, or a validated structured value when declared
87
- ```
94
+ Top-level calls normally return a Run, even when execution fails. The terminal event carries the same outcome when you stream:
88
95
 
89
- ## Runs own top-level lifecycle
96
+ | What happened | Run outcome | Terminal event | What Ruby does |
97
+ | --- | --- | --- | --- |
98
+ | The assembly completed | `completed` | `:run_stop` | Returns the Run |
99
+ | Model, provider, or assembly execution failed | `failed` | `:run_error` | Returns the Run; inspect `run.error` |
100
+ | The deadline stopped work | `partial` | `:run_partial` | Returns the Run with any response produced so far |
101
+ | Cancellation stopped work | `cancelled` | `:run_cancel` | Returns the Run without a response |
102
+ | Tool input or a `ToolError` failed | The model may recover | No terminal event by itself | Gives a safe error result back to the model |
103
+ | Input, configuration, or resources failed before a Run could start | No Run exists | None | Raises the exception |
90
104
 
91
- A `LittleGhost::Run` owns one top-level agent or workflow execution. It opens the session, workspace, sandbox, entrypoint, and registered resources, then closes owned resources in reverse order.
105
+ Unexpected Tool exception messages are hidden from the model. The original exception remains available to trusted application callbacks and diagnostics.
92
106
 
93
- The run is both executable and enumerable. `#call` consumes it; `#each` streams `LittleGhost::StreamEvent` objects. After termination, the run reports one outcome: completed, failed, partial at a deadline, or cancelled. It also exposes the final response, result, usage, and error.
107
+ Failures while closing resources, delivering events, or reporting instrumentation sit outside the normal result path. They raise a Ruby exception because LittleGhost can no longer promise that it delivered a clean ending. [Running in Production](production.md) covers that boundary where applications supervise and shut down work.
94
108
 
95
- An `Invocation` is the request envelope. It normalizes the current message and history, generates missing identifiers, and retains application-specific fields with indifferent string and symbol keys. Caller identity remains explicit. If session persistence needs tenant isolation, derive its actor from trusted authentication state; never trust a model-supplied or unverified request field.
109
+ ## An Assembly can look like one Agent
96
110
 
97
- ## Tools are validated application boundaries
111
+ One model loop is not always enough. LittleGhost calls any unit that a caller can invoke like an Agent an **Assembly**.
98
112
 
99
- `HelpCenterLookupTool` exposes exactly one operation to the model:
113
+ An Agent is the smallest Assembly. Workflow, Swarm, and Graph coordinate several participants while preserving the same entrypoints:
100
114
 
101
115
  ```ruby
102
- class HelpCenterLookupTool < LittleGhost::Tool
103
- description "Look up a help center entry by topic."
104
- input_schema(
105
- type: "object",
106
- properties: {topic: {type: "string"}},
107
- required: ["topic"],
108
- additionalProperties: false
109
- )
110
-
111
- def call(input)
112
- HelpCenterRepository.fetch(input.fetch("topic"))
113
- end
114
- end
116
+ CustomerSupportAgent.ask(question)
117
+ ResponseWorkflow.ask(question)
118
+ ProblemSolverSwarm.ask(question)
119
+ SupportFlowGraph.ask(question)
115
120
  ```
116
121
 
117
- LittleGhost validates the model's input before invoking `#call`. Hashes and arrays returned by a tool are JSON-encoded; other values become text. Expected application failures can raise `LittleGhost::ToolError`; unexpected exception messages are sanitized before they reach model context.
122
+ 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.
118
123
 
119
- Validation is not authorization. A tool that reads customer records, writes files, executes processes, or calls a network service must enforce the application's trust rules itself. The built-in unrestricted sandbox executes with the Ruby process's permissions and is not a security boundary. Configure an isolated sandbox before exposing filesystem or shell tools to untrusted work.
124
+ ## Choose who controls the next step
120
125
 
121
- ## Subagents are model-directed delegation
126
+ The coordination types differ mainly in who decides what happens next:
122
127
 
123
- Declaring `ResearchAgent` as a subagent gives `CustomerSupportAgent` a configured set of tools for spawning, messaging, interrupting, waiting for, and listing research work:
128
+ | Need | Choose | Who controls the next step? |
129
+ | --- | --- | --- |
130
+ | One model-driven behavior | Agent | The active model loop |
131
+ | A model should delegate a named task | Subagent | The parent model |
132
+ | Ruby should enforce ordering or branching | Workflow | The workflow's Ruby code |
133
+ | Specialists should choose permitted handoffs | Swarm | The active agent |
134
+ | Allowed routes should be visible in advance | Graph | Declared nodes and edges |
124
135
 
125
- ```ruby
126
- class ResearchAgent < LittleGhost::Agent
127
- description "Investigates support questions that need broader research."
128
- model "customer_support.research"
129
- system_prompt "Return a concise evidence summary."
130
- end
136
+ ### Subagents bring in a specialist
137
+
138
+ 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.
131
139
 
140
+ ```ruby
132
141
  class CustomerSupportAgent < LittleGhost::Agent
133
- model "customer_support"
134
- tools HelpCenterLookupTool
142
+ model "openrouter:openai/gpt-5.6-luna"
135
143
  subagent ResearchAgent, kind: "research"
136
144
  end
137
145
  ```
138
146
 
139
- The model decides whether to delegate and how to use the returned research. Each child declares its own tools, so access remains visible at the class receiving it. Subagent work can run concurrently and respects the configured turn, concurrency, depth, and time limits. Conversations can persist when a session store exists; `persist: false` keeps a declaration invocation-local.
147
+ 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.
140
148
 
141
- Use an agent as an ordinary tool with `agent_as_tool` when one request and one result is enough. Use a subagent when the parent needs an addressable worker with follow-ups, progress, interruption, or durable conversation identity.
149
+ ### Workflows make Ruby the coordinator
142
150
 
143
- ## Workflows are application-directed composition
151
+ 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.
144
152
 
145
- Some customer support requests must always be researched before a response is written. Put that invariant in Ruby rather than asking the model to remember it:
153
+ `invoke` prepares a lazy child call. Reading `.output` runs an intermediate child. Return the final `invoke` itself, without reading its output, so that answer can stream to the caller.
146
154
 
147
155
  ```ruby
148
156
  class ResponseWorkflow < LittleGhost::Workflow
@@ -150,9 +158,7 @@ class ResponseWorkflow < LittleGhost::Workflow
150
158
 
151
159
  def perform
152
160
  research = invoke(ResearchAgent).output
153
-
154
161
  invoke CustomerSupportAgent, input: <<~PROMPT
155
- Customer request:
156
162
  #{input.text}
157
163
 
158
164
  Research:
@@ -162,62 +168,80 @@ class ResponseWorkflow < LittleGhost::Workflow
162
168
  end
163
169
  ```
164
170
 
165
- `#invoke` builds a lazy agent invocation. Calling `#output` consumes an intermediate invocation; `#perform` must return its final invocation unconsumed so LittleGhost can stream that agent to the original caller. Input, history, state, settings, cancellation, deadline, template values, and trace parentage flow through the workflow, while intermediate usage is added to the terminal result.
171
+ Workflow children receive the caller's history and application context by default. Pass `history: []`, `context: {}`, or redacted values when a participant should receive less.
166
172
 
167
- A workflow is an explicit entrypoint on a run:
173
+ ### Swarms let agents hand work to one another
174
+
175
+ 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.
168
176
 
169
177
  ```ruby
170
- runtime = LittleGhost::Runtime.new(configuration: LittleGhost.configuration)
171
- run = runtime.build_run(
172
- {message: "Review this unusual refund request"},
173
- agent_class: CustomerSupportAgent,
174
- entrypoint_class: ResponseWorkflow
175
- ).call
176
-
177
- puts run.response
178
+ class ProblemSolverSwarm < LittleGhost::Swarm
179
+ member TriageAgent
180
+ member BillingAgent
181
+ member AccountAgent
182
+
183
+ start TriageAgent
184
+ handoff TriageAgent, to: [BillingAgent, AccountAgent]
185
+ end
178
186
  ```
179
187
 
180
- Choose a subagent when delegation is part of the model's judgment. Choose a workflow when ordering and branching are application invariants. They can coexist: `ResponseWorkflow` can always collect baseline research, while `CustomerSupportAgent` can still delegate a new question that arises while drafting the response.
188
+ 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. Treat every handoff message as untrusted model input.
181
189
 
182
- ## Structured results separate data from prose
190
+ ### Graphs make routes visible
183
191
 
184
- An agent that feeds application code can declare a strict JSON object schema:
192
+ A **Graph** connects named Assembly nodes with declared edges. Nodes can contain Agents, Workflows, Swarms, or other Graphs.
185
193
 
186
194
  ```ruby
187
- class ResearchAgent < LittleGhost::Agent
188
- model "customer_support.research"
189
- result_schema(
190
- {
191
- type: "object",
192
- properties: {
193
- summary: {type: "string"},
194
- sources: {type: "array", items: {type: "string"}}
195
- },
196
- required: %w[summary sources],
197
- additionalProperties: false
198
- },
199
- name: "support_research"
200
- )
195
+ class SupportFlowGraph < LittleGhost::Graph
196
+ node :triage, TriageAgent
197
+ node :billing, BillingAgent
198
+ node :general, CustomerSupportAgent
199
+ node :respond, CustomerSupportAgent
200
+
201
+ start :triage
202
+ edge :triage, :billing do |state|
203
+ state.result(:triage).output == "billing"
204
+ end
205
+ edge :triage, :general
206
+ edge :billing, :respond
207
+ edge :general, :respond
208
+ finish :respond
201
209
  end
202
210
  ```
203
211
 
204
- LittleGhost selects provider-native structured output when the resolved model advertises it, or a strict terminal tool when supported. The locally validated value is available through `RunResult#structured_result` and `RunResult#output`. Invalid output receives one repair attempt, then raises `LittleGhost::StructuredResultError`.
212
+ Graph nodes do not receive caller history or application context unless they opt in. They still receive the original request and the outputs routed to them. Use edge input mappers to choose or redact what moves forward.
213
+
214
+ ## Class definitions first, builders when needed
215
+
216
+ Named classes are the default way to organize reusable behavior. They are readable, load through normal Ruby conventions, and give the coordination style a visible name such as `ResponseWorkflow` or `SupportFlowGraph`.
205
217
 
206
- Use structured results when code consumes fields. Keep ordinary text when a human is the final consumer.
218
+ Every assembly class can also produce a mutable builder:
207
219
 
208
- ## Sessions preserve conversation, streams expose progress
220
+ ```ruby
221
+ graph = SupportFlowGraph.to_builder
222
+ graph.node :audit, AuditAgent
223
+ graph.edge :respond, :audit
224
+ graph.finish :audit
225
+ graph.validate!
226
+ run = graph.ask("Review order 481")
227
+ ```
209
228
 
210
- The default session store is in-memory. A configured `SessionStore` can load history and state before an agent runs and checkpoint coherent turns as work progresses. The application must supply stable session and actor identifiers when it wants continuity and isolation.
229
+ Use a builder when trusted application configuration decides the participants or routes. Each run gets a fixed copy of the builder as it looked when the run began, so later edits affect later runs. Ruby callbacks still see any application objects they captured.
211
230
 
212
- Streams expose generic framework events rather than provider wire formats. Consumers can render text deltas, observe tool or subagent activity, collect usage, and react to terminal outcomes without coupling to OpenAI, OpenRouter, or Bedrock. The optional AG-UI adapter translates the same events at an interface boundary.
231
+ ## One result, including the journey
213
232
 
214
- ## Keep the boundary visible
233
+ Every assembly produces the same top-level `Run` and final `RunResult`. Composite assemblies also keep a size-limited record of the participants that ran:
234
+
235
+ ```ruby
236
+ run = SupportFlowGraph.ask("Why was I charged twice?")
237
+
238
+ run.response
239
+ run.result.steps
240
+ run.result.trajectory.transitions
241
+ ```
215
242
 
216
- The core design can be summarized as four choices:
243
+ This shows callers which participants ran without including raw provider responses. A Swarm or Graph may hide intermediate model events from the public stream so the response stays coherent. That is a presentation choice, not a privacy boundary: routed outputs and step summaries still exist.
217
244
 
218
- - Put shared construction and provider policy in configuration; use inline declarations or independent YAML files according to the application's needs.
219
- - Put model behavior and available capabilities on agent classes.
220
- - Put privileged application operations behind narrow, authorized tools.
221
- - Put mandatory ordering in workflows; leave optional delegation to subagents.
245
+ 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.
222
246
 
223
- Return to [Getting Started](getting_started.md) for the complete first-run setup. The API reference covers exact signatures and lifecycle details for `LittleGhost::Runtime`, `LittleGhost::Run`, `LittleGhost::Agent`, `LittleGhost::Tool`, `LittleGhost::Workflow`, and `LittleGhost::ModelResolver`.
247
+ Continue with [Compose Agents](assemblies.md) to put several agents to work together. If you are ready to connect the feature to a real application, jump to [Running in Production](production.md).