vsm 0.0.1 → 0.2.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.
- checksums.yaml +4 -4
- data/.claude/settings.local.json +17 -0
- data/CLAUDE.md +134 -0
- data/README.md +675 -17
- data/Rakefile +1 -5
- data/examples/01_echo_tool.rb +51 -0
- data/examples/02_openai_streaming.rb +73 -0
- data/examples/02b_anthropic_streaming.rb +58 -0
- data/examples/02c_gemini_streaming.rb +60 -0
- data/examples/03_openai_tools.rb +106 -0
- data/examples/03b_anthropic_tools.rb +93 -0
- data/examples/03c_gemini_tools.rb +95 -0
- data/examples/05_mcp_server_and_chattty.rb +63 -0
- data/examples/06_mcp_mount_reflection.rb +45 -0
- data/examples/07_connect_claude_mcp.rb +78 -0
- data/examples/08_custom_chattty.rb +63 -0
- data/examples/09_mcp_with_llm_calls.rb +49 -0
- data/examples/10_meta_read_only.rb +56 -0
- data/exe/vsm +17 -0
- data/lib/vsm/async_channel.rb +44 -0
- data/lib/vsm/capsule.rb +46 -0
- data/lib/vsm/cli.rb +78 -0
- data/lib/vsm/drivers/anthropic/async_driver.rb +210 -0
- data/lib/vsm/drivers/family.rb +16 -0
- data/lib/vsm/drivers/gemini/async_driver.rb +149 -0
- data/lib/vsm/drivers/openai/async_driver.rb +202 -0
- data/lib/vsm/dsl.rb +80 -0
- data/lib/vsm/dsl_mcp.rb +36 -0
- data/lib/vsm/executors/fiber_executor.rb +10 -0
- data/lib/vsm/executors/thread_executor.rb +19 -0
- data/lib/vsm/generator/new_project.rb +154 -0
- data/lib/vsm/generator/templates/Gemfile.erb +9 -0
- data/lib/vsm/generator/templates/README_md.erb +40 -0
- data/lib/vsm/generator/templates/Rakefile.erb +5 -0
- data/lib/vsm/generator/templates/bin_console.erb +11 -0
- data/lib/vsm/generator/templates/bin_setup.erb +7 -0
- data/lib/vsm/generator/templates/exe_name.erb +34 -0
- data/lib/vsm/generator/templates/gemspec.erb +24 -0
- data/lib/vsm/generator/templates/gitignore.erb +10 -0
- data/lib/vsm/generator/templates/lib_name_rb.erb +9 -0
- data/lib/vsm/generator/templates/lib_organism_rb.erb +44 -0
- data/lib/vsm/generator/templates/lib_ports_chat_tty_rb.erb +12 -0
- data/lib/vsm/generator/templates/lib_tools_read_file_rb.erb +32 -0
- data/lib/vsm/generator/templates/lib_version_rb.erb +6 -0
- data/lib/vsm/homeostat.rb +19 -0
- data/lib/vsm/lens/event_hub.rb +73 -0
- data/lib/vsm/lens/server.rb +188 -0
- data/lib/vsm/lens/stats.rb +58 -0
- data/lib/vsm/lens/tui.rb +88 -0
- data/lib/vsm/lens.rb +79 -0
- data/lib/vsm/mcp/client.rb +80 -0
- data/lib/vsm/mcp/jsonrpc.rb +92 -0
- data/lib/vsm/mcp/remote_tool_capsule.rb +35 -0
- data/lib/vsm/message.rb +6 -0
- data/lib/vsm/meta/snapshot_builder.rb +121 -0
- data/lib/vsm/meta/snapshot_cache.rb +25 -0
- data/lib/vsm/meta/support.rb +35 -0
- data/lib/vsm/meta/tools.rb +498 -0
- data/lib/vsm/meta.rb +59 -0
- data/lib/vsm/observability/ledger.rb +25 -0
- data/lib/vsm/port.rb +11 -0
- data/lib/vsm/ports/chat_tty.rb +112 -0
- data/lib/vsm/ports/mcp/server_stdio.rb +101 -0
- data/lib/vsm/roles/coordination.rb +49 -0
- data/lib/vsm/roles/governance.rb +9 -0
- data/lib/vsm/roles/identity.rb +11 -0
- data/lib/vsm/roles/intelligence.rb +172 -0
- data/lib/vsm/roles/operations.rb +33 -0
- data/lib/vsm/runtime.rb +18 -0
- data/lib/vsm/tool/acts_as_tool.rb +20 -0
- data/lib/vsm/tool/capsule.rb +12 -0
- data/lib/vsm/tool/descriptor.rb +16 -0
- data/lib/vsm/version.rb +1 -1
- data/lib/vsm.rb +43 -0
- data/llms.txt +322 -0
- data/mcp_update.md +162 -0
- metadata +93 -31
- data/.rubocop.yml +0 -8
data/llms.txt
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
|
|
2
|
+
LLMS CONTEXT FILE — VSM (Viable Systems for Agents) GEM
|
|
3
|
+
=======================================================
|
|
4
|
+
|
|
5
|
+
Audience: Large Language Models (LLMs) acting as coding assistants and human contributors.
|
|
6
|
+
Goal: Provide all key context to safely modify, extend, and use the VSM gem as a framework for agentic CLIs (e.g., `airb`).
|
|
7
|
+
|
|
8
|
+
— TL;DR —
|
|
9
|
+
- VSM is a small, async, message-driven runtime for building recursive “capsules” that each contain five named systems:
|
|
10
|
+
Operations, Coordination, Intelligence, Governance, Identity. Monitoring (observability) is also provided.
|
|
11
|
+
- Tools are implemented as *capsules* that *opt-in* to a tool interface (`ActsAsTool`) with JSON Schema descriptors.
|
|
12
|
+
- The runtime is fiber-based (`async` gem). Tool execution can run in parallel via executors (`:fiber`, `:thread`, optional `:ractor`/`:subprocess` later).
|
|
13
|
+
- Intelligence integrates provider drivers (OpenAI, Anthropic, Gemini) that support *structured tool calls* and (for OpenAI/Anthropic) *streaming*.
|
|
14
|
+
- A built-in “Lens” web visualizer (SSE) streams live events from the bus; enable with one call.
|
|
15
|
+
- Use the DSL to assemble a top-level capsule (the “organism”) and optional sub-capsules (recursive sub-agents or tools).
|
|
16
|
+
|
|
17
|
+
--------------------------------------------------------------------------------
|
|
18
|
+
1) REPO LAYOUT (EXPECTED FILES)
|
|
19
|
+
--------------------------------------------------------------------------------
|
|
20
|
+
lib/
|
|
21
|
+
vsm.rb # top-level requires
|
|
22
|
+
vsm/message.rb # Message struct
|
|
23
|
+
vsm/async_channel.rb # async bus (fibers)
|
|
24
|
+
vsm/homeostat.rb # budgets/alerts (minimal)
|
|
25
|
+
vsm/observability/ledger.rb # Monitoring role: JSONL event ledger
|
|
26
|
+
vsm/roles/
|
|
27
|
+
operations.rb # runs tools (capsules) via executors
|
|
28
|
+
coordination.rb # scheduling, floor control, turn end
|
|
29
|
+
intelligence.rb # abstract; apps subclass this
|
|
30
|
+
governance.rb # policy/budgets/confirmation hooks
|
|
31
|
+
identity.rb # invariants/escalation
|
|
32
|
+
vsm/tool/
|
|
33
|
+
descriptor.rb # name/description/schema → provider shapes
|
|
34
|
+
acts_as_tool.rb # mixin to mark capsules as tools
|
|
35
|
+
capsule.rb # base tool capsule (implements #run)
|
|
36
|
+
vsm/executors/
|
|
37
|
+
fiber_executor.rb # default (IO-bound)
|
|
38
|
+
thread_executor.rb # CPU-ish or blocking libs
|
|
39
|
+
# (optional) ractor_executor.rb / subprocess_executor.rb
|
|
40
|
+
vsm/capsule.rb # Capsule: wires systems, async run loop
|
|
41
|
+
vsm/dsl.rb # DSL for composing organisms & children
|
|
42
|
+
vsm/port.rb # adapter base (CLI/TUI/HTTP/etc.)
|
|
43
|
+
vsm/runtime.rb # boot helper: start capsule + ports
|
|
44
|
+
vsm/drivers/
|
|
45
|
+
family.rb # returns :openai | :anthropic | :gemini
|
|
46
|
+
openai/async_driver.rb # SSE streaming + tools
|
|
47
|
+
anthropic/async_driver.rb # SSE streaming + tool_use blocks
|
|
48
|
+
gemini/async_driver.rb # non-streaming MVP + functionCall
|
|
49
|
+
vsm/lens.rb # Lens.attach!(capsule, ...)
|
|
50
|
+
vsm/lens/event_hub.rb # ring buffer + fan-out
|
|
51
|
+
vsm/lens/server.rb # Rack app + SSE + tiny HTML
|
|
52
|
+
|
|
53
|
+
spec/ # RSpec tests (smoke + providers + routing)
|
|
54
|
+
examples/ # small runnable demos
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
--------------------------------------------------------------------------------
|
|
58
|
+
2) DESIGN GOALS
|
|
59
|
+
--------------------------------------------------------------------------------
|
|
60
|
+
- Small surface, idiomatic Ruby (SOLID/POODR), high cohesion/low coupling.
|
|
61
|
+
- Recursion-by-default: a Capsule can contain child Capsules.
|
|
62
|
+
- First-class asynchrony: non-blocking I/O; parallel tool calls where safe.
|
|
63
|
+
- Provider-agnostic Intelligence with a stable, minimal event API:
|
|
64
|
+
:assistant_delta, :assistant_final, :tool_calls.
|
|
65
|
+
- Observability out-of-the-box: JSONL ledger + SSE Lens.
|
|
66
|
+
- Safety hooks live in Governance (path sandbox, confirmations, budgets).
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
--------------------------------------------------------------------------------
|
|
70
|
+
3) MESSAGE MODEL
|
|
71
|
+
--------------------------------------------------------------------------------
|
|
72
|
+
Struct: VSM::Message.new(
|
|
73
|
+
kind:, # Symbol — :user, :assistant_delta, :assistant, :tool_call, :tool_result, :plan, :policy, :audit, :confirm_request, :confirm_response, :progress
|
|
74
|
+
payload:, # Object/String — event-specific data (small where possible)
|
|
75
|
+
path:, # Array<Symbol> — addressing (e.g., [:airb, :operations, :read_file])
|
|
76
|
+
corr_id:, # String — correlates tool_call <-> tool_result
|
|
77
|
+
meta: # Hash — session_id, tool name, budgets, severity, etc.
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
Guidance for LLMs:
|
|
81
|
+
- Always set meta.session_id for multi-turn sessions.
|
|
82
|
+
- When emitting tool events, fill meta.tool and corr_id for pairing.
|
|
83
|
+
- Keep payload compact; include previews for large data (full bodies may be written to disk separately if needed).
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
--------------------------------------------------------------------------------
|
|
87
|
+
4) CAPSULE + SYSTEMS (THE “ORG” SPINE)
|
|
88
|
+
--------------------------------------------------------------------------------
|
|
89
|
+
Capsule contains:
|
|
90
|
+
- bus: AsyncChannel (fiber-friendly queue + subscribers)
|
|
91
|
+
- homeostat: budgets/alerts (minimal for MVP)
|
|
92
|
+
- roles: five named systems
|
|
93
|
+
- Operations: runs tools, dispatches to child tool-capsules
|
|
94
|
+
- Coordination: schedules messages; grants floor per session; turn end
|
|
95
|
+
- Intelligence: orchestrates LLM driver; streams deltas; emits tool_calls
|
|
96
|
+
- Governance: policy gates (sandboxing, confirmation, budgets)
|
|
97
|
+
- Identity: invariants, escalation to owner/user
|
|
98
|
+
- children: Hash of name → child capsule (often tool capsules)
|
|
99
|
+
|
|
100
|
+
Dispatch order (typical): Operations → Intelligence → Identity
|
|
101
|
+
(Operations consumes :tool_call; Intelligence consumes :user/:tool_result; Identity handles policy updates/broadcasts.)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
--------------------------------------------------------------------------------
|
|
105
|
+
5) ASYNCHRONY & PARALLELISM
|
|
106
|
+
--------------------------------------------------------------------------------
|
|
107
|
+
- The bus is fiber-based (`async` gem). Capsule.run loops on bus.pop and lets Coordination drain/schedule messages.
|
|
108
|
+
- Operations executes each tool_call concurrently via an Executor:
|
|
109
|
+
- :fiber (default) for IO-aware code
|
|
110
|
+
- :thread for brief CPU spikes or blocking C libs
|
|
111
|
+
- (:ractor/:subprocess) later for isolation or heavy CPU
|
|
112
|
+
- Use Async::Semaphore to cap per-tool concurrency if needed.
|
|
113
|
+
- Coordination.wait_for_turn_end(session_id) enables CLI ports to block until the assistant final is emitted for the turn.
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
--------------------------------------------------------------------------------
|
|
117
|
+
6) TOOLS AS CAPSULES
|
|
118
|
+
--------------------------------------------------------------------------------
|
|
119
|
+
Implement a tool by subclassing VSM::ToolCapsule and including ActsAsTool:
|
|
120
|
+
|
|
121
|
+
class MyTool < VSM::ToolCapsule
|
|
122
|
+
tool_name "search_repo"
|
|
123
|
+
tool_description "Search codebase by regex"
|
|
124
|
+
tool_schema({
|
|
125
|
+
type: "object",
|
|
126
|
+
properties: { pattern: { type: "string" }, path: { type: "string" } },
|
|
127
|
+
required: ["pattern"]
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
def execution_mode = :thread # optional; defaults to :fiber
|
|
131
|
+
def run(args)
|
|
132
|
+
# return a String or small JSON-compatible object
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
Notes:
|
|
137
|
+
- The JSON Schema should be compact and valid for OpenAI/Anthropic/Gemini.
|
|
138
|
+
- Governance is injected into tool capsules (if they expose #governance=), allowing helpers like safe_path().
|
|
139
|
+
- Keep results small. For big outputs, summarize or write artifacts to files and return a reference.
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
--------------------------------------------------------------------------------
|
|
143
|
+
7) INTELLIGENCE & PROVIDER DRIVERS
|
|
144
|
+
--------------------------------------------------------------------------------
|
|
145
|
+
- Intelligence subclasses handle per-session conversation history and call a driver’s run!(conversation:, tools:, policy:) which yields three events:
|
|
146
|
+
- [:assistant_delta, String] — stream partial text
|
|
147
|
+
- [:assistant_final, String] — final text for the turn (may be empty if only tool calls)
|
|
148
|
+
- [:tool_calls, Array<Hash>] — each { id:, name:, arguments: Hash }
|
|
149
|
+
- Conversation messages passed into drivers are hashes like:
|
|
150
|
+
{ role: "system"|"user"|"assistant"|"tool", content: String, tool_call_id?: String }
|
|
151
|
+
|
|
152
|
+
Providers:
|
|
153
|
+
- OpenAI::DriverAsync — SSE streaming; tools in choices[].delta.tool_calls; pass tools via `[{type:"function", function:{name, description, parameters}}]`.
|
|
154
|
+
- Anthropic::DriverAsync — SSE streaming; `tool_use` content blocks with `input_json_delta` fragments; pass tools via `[{name, description, input_schema}]`; tool_result fed back as a user content block `{type:"tool_result", tool_use_id, content}`.
|
|
155
|
+
- Gemini::DriverAsync — non-streaming MVP; declare tools via `function_declarations`; receive `functionCall`; reply next turn with `functionResponse`.
|
|
156
|
+
|
|
157
|
+
Driver selection:
|
|
158
|
+
- VSM::Intelligence::DriverFamily.of(@driver) → :openai | :anthropic | :gemini.
|
|
159
|
+
- Build provider-specific tool arrays from VSM::Tool::Descriptor:
|
|
160
|
+
- to_openai_tool, to_anthropic_tool, to_gemini_tool.
|
|
161
|
+
|
|
162
|
+
Important rules for LLMs modifying Intelligence:
|
|
163
|
+
- Do not parse tool calls from free-form text. Always use structured tool-calling outputs from drivers.
|
|
164
|
+
- Maintain conversation faithfully; append assistant/tool messages exactly as providers expect.
|
|
165
|
+
- Always emit :assistant_delta before :assistant when streaming text.
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
--------------------------------------------------------------------------------
|
|
169
|
+
8) GOVERNANCE & IDENTITY
|
|
170
|
+
--------------------------------------------------------------------------------
|
|
171
|
+
- Governance.enforce(message) wraps routing. Add sandboxing, diff previews, confirmations, budgets, and timeouts here.
|
|
172
|
+
- Emit :confirm_request when needed; the Port must collect a :confirm_response.
|
|
173
|
+
- Identity holds invariants (e.g., “stay in workspace”), escalates algedonic alerts (homeostat.alarm?).
|
|
174
|
+
|
|
175
|
+
LLM policy changes should emit a :policy message that Identity can broadcast to children if necessary.
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
--------------------------------------------------------------------------------
|
|
179
|
+
9) PORTS (INTERFACES)
|
|
180
|
+
--------------------------------------------------------------------------------
|
|
181
|
+
- Base: VSM::Port with #ingress(event) and #render_out(message).
|
|
182
|
+
- ChatTTY port: reads stdin lines, emits :user with meta.session_id; renders :assistant_delta (stream) and :assistant (final), handles :confirm_request → :confirm_response.
|
|
183
|
+
- Other ports: CommandTTY (one-shot task), HTTP, WebSocket, MCP client/server ports (planned), TUI.
|
|
184
|
+
|
|
185
|
+
Guidance for LLMs:
|
|
186
|
+
- Keep ports thin. No policy or LLM logic in ports.
|
|
187
|
+
- Always pass session_id; grant floor in Coordination for deterministic streaming.
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
--------------------------------------------------------------------------------
|
|
191
|
+
10) OBSERVABILITY (MONITORING + LENS)
|
|
192
|
+
--------------------------------------------------------------------------------
|
|
193
|
+
- Monitoring subscribes to the bus and appends JSONL to .vsm.log.jsonl.
|
|
194
|
+
- Lens is a tiny Rack app serving an SSE `/events` feed with a simple HTML viewer.
|
|
195
|
+
- Enable in apps:
|
|
196
|
+
VSM::Lens.attach!(capsule, host: "127.0.0.1", port: 9292, token: ENV["VSM_LENS_TOKEN"])
|
|
197
|
+
|
|
198
|
+
Lens best practices:
|
|
199
|
+
- Include meta.session_id, path, corr_id, and meta.tool on events.
|
|
200
|
+
- Keep payload small to avoid UI lag; the server already truncates strings.
|
|
201
|
+
- For multi-process swarms, add a RemotePublisher that forwards events to one hub (future).
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
--------------------------------------------------------------------------------
|
|
205
|
+
11) DSL FOR ASSEMBLY
|
|
206
|
+
--------------------------------------------------------------------------------
|
|
207
|
+
Example organism:
|
|
208
|
+
|
|
209
|
+
org = VSM::DSL.define(:airb) do
|
|
210
|
+
identity klass: MyIdentity, args: { identity: "airb", invariants: ["stay in workspace"] }
|
|
211
|
+
governance klass: MyGovernance, args: { workspace_root: Dir.pwd }
|
|
212
|
+
coordination klass: VSM::Coordination
|
|
213
|
+
intelligence klass: MyIntelligence, args: { driver: my_driver }
|
|
214
|
+
monitoring klass: VSM::Monitoring
|
|
215
|
+
|
|
216
|
+
operations do
|
|
217
|
+
capsule :list_files, klass: Tools::ListFiles
|
|
218
|
+
capsule :read_file, klass: Tools::ReadFile
|
|
219
|
+
capsule :edit_file, klass: Tools::EditFile
|
|
220
|
+
# capsule :editor, klass: Capsules::Editor (full sub-agent capsule)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
Start:
|
|
225
|
+
VSM::Runtime.start(org, ports: [ChatTTY.new(capsule: org)])
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
--------------------------------------------------------------------------------
|
|
229
|
+
12) PROVIDER CONFIG (ENV VARS)
|
|
230
|
+
--------------------------------------------------------------------------------
|
|
231
|
+
- OPENAI_API_KEY, AIRB_MODEL (e.g., "gpt-4o-mini")
|
|
232
|
+
- ANTHROPIC_API_KEY, AIRB_MODEL (e.g., "claude-3-5-sonnet-latest")
|
|
233
|
+
- GEMINI_API_KEY, AIRB_MODEL (e.g., "gemini-2.0-flash-001")
|
|
234
|
+
- AIRB_PROVIDER = openai | anthropic | gemini
|
|
235
|
+
- VSM_LENS=1, VSM_LENS_PORT=9292, VSM_LENS_TOKEN=...
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
--------------------------------------------------------------------------------
|
|
239
|
+
13) CODING STANDARDS (FOR LLM CHANGES)
|
|
240
|
+
--------------------------------------------------------------------------------
|
|
241
|
+
- Idiomatic Ruby, small objects, SRP. Keep classes under ~150 LOC when possible.
|
|
242
|
+
- Favor explicit dependencies via initializer args.
|
|
243
|
+
- Avoid global mutable state. If you add caches, use per-capsule fields.
|
|
244
|
+
- Don’t block fibers: for I/O use async-http; for CPU spikes switch to thread executor.
|
|
245
|
+
- Tests for every new adapter/driver parser with fixtures; route tests for message sequencing.
|
|
246
|
+
- Prefer incremental diffs (unified patches) with file paths and clear commit titles:
|
|
247
|
+
- Title: <module>: <short imperative> (e.g., "intelligence/openai: handle empty delta lines")
|
|
248
|
+
- Body: “Why”, “What changed”, “Tests”.
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
--------------------------------------------------------------------------------
|
|
252
|
+
14) TESTING (MINIMUM BASELINE)
|
|
253
|
+
--------------------------------------------------------------------------------
|
|
254
|
+
- Routing smoke test: :tool_call → :tool_result → :assistant
|
|
255
|
+
- Provider parsing tests:
|
|
256
|
+
- OpenAI SSE fixture → emits deltas + final + tool_calls
|
|
257
|
+
- Anthropic SSE fixture with tool_use/input_json_delta → emits tool_calls + final
|
|
258
|
+
- Gemini functionCall fixture → emits tool_calls or final text
|
|
259
|
+
- Governance tests: sandbox rejects path traversal; confirm flow produces :confirm_request
|
|
260
|
+
- Concurrency tests: parallel tool calls produce paired results (different corr_id), no interleaved confusion in Coordination
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
--------------------------------------------------------------------------------
|
|
264
|
+
15) EXTENDING THE FRAMEWORK
|
|
265
|
+
--------------------------------------------------------------------------------
|
|
266
|
+
A) Add a new tool capsule
|
|
267
|
+
- Create class <YourTool> < VSM::ToolCapsule
|
|
268
|
+
- Declare name/description/schema; implement #run; optional #execution_mode
|
|
269
|
+
- Register in operations DSL
|
|
270
|
+
|
|
271
|
+
B) Add a sub-agent capsule
|
|
272
|
+
- Provide its own Operations/Coordination/Intelligence/Governance/Identity (recursive)
|
|
273
|
+
- Optionally include ActsAsTool and expose itself as a parent tool (its #run orchestrates internal steps and returns a string)
|
|
274
|
+
|
|
275
|
+
C) Add a provider
|
|
276
|
+
- Place a new driver_* under lib/vsm/intelligence/<provider>/
|
|
277
|
+
- Yield the same three events (:assistant_delta, :assistant_final, :tool_calls)
|
|
278
|
+
- Add a descriptor conversion if provider needs a special tool shape
|
|
279
|
+
- Update DriverFamily.of to map the class → symbol
|
|
280
|
+
|
|
281
|
+
D) Add MCP support (future plan)
|
|
282
|
+
- Implement Ports::MCP::Server to expose tools via MCP spec
|
|
283
|
+
- Implement Ports::MCP::Client to consume external MCP tools and wrap as tool capsules
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
--------------------------------------------------------------------------------
|
|
287
|
+
16) SAFETY & SECURITY
|
|
288
|
+
--------------------------------------------------------------------------------
|
|
289
|
+
- Never write outside the workspace. Use Governance.safe_path() in tools.
|
|
290
|
+
- Confirm risky writes with :confirm_request → :confirm_response.
|
|
291
|
+
- Add timeouts on tool calls and LLM calls (budget via Homeostat or Governance).
|
|
292
|
+
- Use semaphores to cap concurrency per tool to avoid resource exhaustion.
|
|
293
|
+
- Do not log secrets. Mask API keys and sensitive args before emitting events.
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
--------------------------------------------------------------------------------
|
|
297
|
+
17) KNOWN LIMITATIONS / TODOs
|
|
298
|
+
--------------------------------------------------------------------------------
|
|
299
|
+
- Ractor/Subprocess executors are stubs in some scaffolds; implement when needed.
|
|
300
|
+
- Gemini streaming is not wired yet (MVP uses non-streaming). Add Live/stream endpoints later.
|
|
301
|
+
- Homeostat budgets are placeholders; implement counters and algedonic signals as needed.
|
|
302
|
+
- Lens has minimal UI; extract richer vsm-lens gem when features grow.
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
--------------------------------------------------------------------------------
|
|
306
|
+
18) HOW TO ASK THIS LLM FOR CHANGES
|
|
307
|
+
--------------------------------------------------------------------------------
|
|
308
|
+
- Provide concrete goals and constraints (e.g., “Add a `search_repo` tool that scans *.rb files for a pattern; thread executor; unit tests; and show it in Lens with meta.tool”).
|
|
309
|
+
- Ask for *unified diffs* with exact file paths under lib/ and spec/. Keep patches minimal and focused.
|
|
310
|
+
- Require updates to README snippets if public API changes.
|
|
311
|
+
- Have it add/extend tests and run them locally (`bundle exec rspec`).
|
|
312
|
+
- If the change affects the message kinds or meta fields, ensure Lens/TUI still render sensibly.
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
--------------------------------------------------------------------------------
|
|
316
|
+
19) LICENSE & ATTRIBUTION
|
|
317
|
+
--------------------------------------------------------------------------------
|
|
318
|
+
- MIT by default (edit gemspec if different). Respect third-party licenses for gems you add.
|
|
319
|
+
- Keep provider SDKs optional; current drivers use `async-http` + stdlib only.
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
End of llms.txt.
|
data/mcp_update.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# MCP Integration Plan and Built‑In Ports
|
|
2
|
+
|
|
3
|
+
This document proposes minimal, practical support to:
|
|
4
|
+
- Expose any VSM capsule as an MCP server over stdio (JSON‑RPC) implementing `tools/list` and `tools/call`.
|
|
5
|
+
- Add two reusable ports to VSM: a generic, customizable Chat TTY port and an MCP stdio server port.
|
|
6
|
+
- Dynamically reflect tools from external MCP servers and wrap them as VSM tool capsules.
|
|
7
|
+
|
|
8
|
+
The design uses Ruby’s dynamic capabilities and integrates cleanly with existing VSM roles (Operations, Intelligence, Governance, etc.).
|
|
9
|
+
|
|
10
|
+
## Scope (Phase 1)
|
|
11
|
+
- MCP methods: `tools/list`, `tools/call` only.
|
|
12
|
+
- Transport: JSON‑RPC over stdio (NDJSON framing to start; can evolve to LSP framing without API changes).
|
|
13
|
+
- No additional MCP features (Prompts/Resources/Logs) in this phase.
|
|
14
|
+
|
|
15
|
+
## Components
|
|
16
|
+
- `VSM::Ports::ChatTTY` — Generic, customizable chat terminal port.
|
|
17
|
+
- `VSM::Ports::MCP::ServerStdio` — MCP server over stdio exposing capsule tools.
|
|
18
|
+
- `VSM::MCP::Client` — Thin stdio JSON‑RPC client for MCP reflection and calls.
|
|
19
|
+
- `VSM::MCP::RemoteToolCapsule` — Wraps a remote MCP tool as a local VSM `ToolCapsule`.
|
|
20
|
+
- `VSM::DSL::ChildrenBuilder#mcp_server` — Reflect and register remote tools with include/exclude/prefix controls.
|
|
21
|
+
- (Tiny core tweak) Inject `bus` into children that accept `bus=` to allow rich observability from wrappers.
|
|
22
|
+
|
|
23
|
+
## Design Overview
|
|
24
|
+
- Client reflection: spawn an MCP server process, call `tools/list`, build `RemoteToolCapsule`s per tool, and add them as children. Include/exclude/prefix options shape the local tool namespace.
|
|
25
|
+
- Server exposure: reflect local tools via `tools/list`; on `tools/call`, emit a normal VSM `:tool_call` and await matching `:tool_result` (corr_id = JSON‑RPC id) to reply.
|
|
26
|
+
- Operations routing: unchanged for Phase 1. Reflected tools register as regular children; prefixing avoids collisions. (Optional namespacing router can be added later.)
|
|
27
|
+
- Observability: all bridges emit events into the bus so Lens shows clear lanes (client: `[:mcp, :client, server, tool]`; server: `[:mcp, :server, tool]`).
|
|
28
|
+
- Coexistence: ChatTTY targets the user’s real TTY (e.g., `IO.console`) or stderr; MCP server uses stdio exclusively. They can run together without interfering.
|
|
29
|
+
|
|
30
|
+
## File Layout (proposed)
|
|
31
|
+
- `lib/vsm/ports/chat_tty.rb`
|
|
32
|
+
- `lib/vsm/ports/mcp/server_stdio.rb`
|
|
33
|
+
- `lib/vsm/mcp/jsonrpc.rb` (shared stdio JSON‑RPC util)
|
|
34
|
+
- `lib/vsm/mcp/client.rb`
|
|
35
|
+
- `lib/vsm/mcp/remote_tool_capsule.rb`
|
|
36
|
+
- `lib/vsm/dsl_mcp.rb` (adds `mcp_server` to the DSL ChildrenBuilder)
|
|
37
|
+
- (Core) optional `bus` injection in `lib/vsm/capsule.rb`
|
|
38
|
+
|
|
39
|
+
## APIs and Usage
|
|
40
|
+
|
|
41
|
+
### Expose a Capsule via CLI and MCP (simultaneously)
|
|
42
|
+
```ruby
|
|
43
|
+
require "vsm"
|
|
44
|
+
require "vsm/ports/chat_tty"
|
|
45
|
+
require "vsm/ports/mcp/server_stdio"
|
|
46
|
+
|
|
47
|
+
cap = VSM::DSL.define(:demo) do
|
|
48
|
+
identity klass: VSM::Identity, args: { identity: "demo", invariants: [] }
|
|
49
|
+
governance klass: VSM::Governance
|
|
50
|
+
coordination klass: VSM::Coordination
|
|
51
|
+
intelligence klass: VSM::Intelligence, args: { driver: VSM::Drivers::OpenAI::AsyncDriver.new(api_key: ENV["OPENAI_API_KEY"], model: "gpt-4o-mini") }
|
|
52
|
+
monitoring klass: VSM::Monitoring
|
|
53
|
+
operations do
|
|
54
|
+
# local tools …
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
ports = [
|
|
59
|
+
VSM::Ports::MCP::ServerStdio.new(capsule: cap), # machine IO (stdio)
|
|
60
|
+
VSM::Ports::ChatTTY.new(capsule: cap) # human IO (TTY/console)
|
|
61
|
+
]
|
|
62
|
+
VSM::Runtime.start(cap, ports: ports)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Mount a Remote MCP Server (dynamic reflection)
|
|
66
|
+
```ruby
|
|
67
|
+
require "vsm"
|
|
68
|
+
require "vsm/dsl_mcp"
|
|
69
|
+
|
|
70
|
+
cap = VSM::DSL.define(:with_remote) do
|
|
71
|
+
identity klass: VSM::Identity, args: { identity: "with_remote", invariants: [] }
|
|
72
|
+
governance klass: VSM::Governance
|
|
73
|
+
coordination klass: VSM::Coordination
|
|
74
|
+
intelligence klass: VSM::Intelligence, args: { driver: VSM::Drivers::Anthropic::AsyncDriver.new(api_key: ENV["ANTHROPIC_API_KEY"], model: "claude-sonnet-4.0") }
|
|
75
|
+
monitoring klass: VSM::Monitoring
|
|
76
|
+
operations do
|
|
77
|
+
mcp_server :smith, cmd: "smith-server --stdio", include: %w[search read], prefix: "smith_", env: { "SMITH_TOKEN" => ENV["SMITH_TOKEN"] }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
VSM::Runtime.start(cap, ports: [VSM::Ports::ChatTTY.new(capsule: cap)])
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Filter Tools Offered to the Model (optional)
|
|
85
|
+
```ruby
|
|
86
|
+
class GuardedIntel < VSM::Intelligence
|
|
87
|
+
def offer_tools?(sid, descriptor)
|
|
88
|
+
descriptor.name.start_with?("smith_") # only offer smith_* tools
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Customization (ChatTTY)
|
|
94
|
+
- Constructor options: `input:`, `output:`, `banner:`, `prompt:`, `theme:`.
|
|
95
|
+
- Defaults: reads/writes to `IO.console` if available; otherwise reads are disabled and output goes to a safe stream (stderr/console). Never interferes with MCP stdio.
|
|
96
|
+
- Override points: subclass and override `banner(io)` and/or `render_out(message)` while reusing the main input loop.
|
|
97
|
+
|
|
98
|
+
Example (options only):
|
|
99
|
+
```ruby
|
|
100
|
+
tty = VSM::Ports::ChatTTY.new(
|
|
101
|
+
capsule: cap,
|
|
102
|
+
banner: ->(io) { io.puts "\e[96mMy App\e[0m — welcome!" },
|
|
103
|
+
prompt: "Me> "
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Example (subclass):
|
|
108
|
+
```ruby
|
|
109
|
+
class FancyTTY < VSM::Ports::ChatTTY
|
|
110
|
+
def banner(io)
|
|
111
|
+
io.puts "\e[95m\n ███ MY APP ███\n\e[0m"
|
|
112
|
+
end
|
|
113
|
+
def render_out(m)
|
|
114
|
+
super
|
|
115
|
+
@out.puts("\e[92m✓ #{m.payload.to_s.slice(0,200)}\e[0m") if m.kind == :tool_result
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Coexistence and IO Routing
|
|
121
|
+
- MCP stdio server: reads `$stdin`, writes `$stdout` with strict JSON (one message per line). No TTY assumptions.
|
|
122
|
+
- ChatTTY: prefers `IO.console` for both input and output; falls back to `$stderr` for output and disables input if no TTY is present.
|
|
123
|
+
- Result: Both ports can run in the same process without corrupting MCP stdio.
|
|
124
|
+
|
|
125
|
+
## Observability
|
|
126
|
+
- Client wrapper emits `:progress`/`:audit` with `path: [:mcp, :client, server, tool]` around calls.
|
|
127
|
+
- Server port emits `:audit` and wraps `tools/call` into standard `:tool_call`/`:tool_result` with `corr_id` mirrored to JSON‑RPC id.
|
|
128
|
+
- Lens will show clear lanes and full payloads, subject to Governance redaction (if any).
|
|
129
|
+
|
|
130
|
+
## Governance and Operations
|
|
131
|
+
- Operations: unchanged; executes capsules for `:tool_call` and emits `:tool_result`.
|
|
132
|
+
- Governance: gate by name/prefix/regex; apply timeouts/rate limits/confirmations; redact args/results in Lens if needed.
|
|
133
|
+
- Execution mode: remote wrappers default to `:thread` to avoid blocking the reactor on stdio I/O.
|
|
134
|
+
|
|
135
|
+
## Configuration and Authentication
|
|
136
|
+
- Default via ENV (e.g., tokens/keys). Per‑mount overrides available through `mcp_server env: { … }`.
|
|
137
|
+
- CLI flags can be introduced later in a helper script if needed.
|
|
138
|
+
|
|
139
|
+
## Backward Compatibility
|
|
140
|
+
- No changes to `airb`. `VSM::Ports::ChatTTY` is a reusable, minimal alternative for new apps.
|
|
141
|
+
|
|
142
|
+
## Future Extensions (not in Phase 1)
|
|
143
|
+
- Namespaced mounts (`smith.search`) with a tiny router enhancement in Operations.
|
|
144
|
+
- Code generation flow (`vsm mcp import …`) to create durable wrappers.
|
|
145
|
+
- Additional MCP features (prompts/resources/logs) and WebSocket transport.
|
|
146
|
+
- Web interaction port: HTTP chat with customizable UI surfaces.
|
|
147
|
+
|
|
148
|
+
## Milestones
|
|
149
|
+
1) Implement ports and client/wrapper (files above), plus optional `bus` injection.
|
|
150
|
+
2) Add small README/usage and example snippet in `examples/`.
|
|
151
|
+
3) Manual tests:
|
|
152
|
+
- Start capsule with both ChatTTY and MCP ports; verify no IO collision.
|
|
153
|
+
- Reflect a known MCP server; verify tool listing and calls.
|
|
154
|
+
- Lens shows client/server lanes with corr_id continuity.
|
|
155
|
+
4) Optional: DSL include/exclude/prefix validation and guardrails.
|
|
156
|
+
|
|
157
|
+
## Acceptance Criteria
|
|
158
|
+
- Starting a capsule with `VSM::Ports::MCP::ServerStdio` exposes working `tools/list` and `tools/call` on stdio.
|
|
159
|
+
- Starting a capsule with `VSM::Ports::ChatTTY` provides a working chat loop; banner/prompt are overridable without re‑implementing the loop.
|
|
160
|
+
- Running both ports concurrently does not corrupt MCP stdio.
|
|
161
|
+
- Reflecting a remote MCP server via `mcp_server` registers local tool capsules that work with `Intelligence` tool‑calling.
|
|
162
|
+
- Lens displays meaningful events for both client and server paths.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vsm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Scott Werner
|
|
@@ -37,6 +37,20 @@ dependencies:
|
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '0.90'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: rack
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '3.2'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '3.2'
|
|
40
54
|
- !ruby/object:Gem::Dependency
|
|
41
55
|
name: rspec
|
|
42
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,60 +66,108 @@ dependencies:
|
|
|
52
66
|
- !ruby/object:Gem::Version
|
|
53
67
|
version: '3.13'
|
|
54
68
|
- !ruby/object:Gem::Dependency
|
|
55
|
-
name:
|
|
69
|
+
name: async-rspec
|
|
56
70
|
requirement: !ruby/object:Gem::Requirement
|
|
57
71
|
requirements:
|
|
58
72
|
- - "~>"
|
|
59
73
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: '1.
|
|
74
|
+
version: '1.17'
|
|
61
75
|
type: :development
|
|
62
76
|
prerelease: false
|
|
63
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
78
|
requirements:
|
|
65
79
|
- - "~>"
|
|
66
80
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: '1.
|
|
81
|
+
version: '1.17'
|
|
68
82
|
description: |
|
|
69
83
|
VSM is a small Ruby framework for building agentic systems using a
|
|
70
84
|
Viable System Model–style architecture. It gives you Capsules: self‑contained components
|
|
71
85
|
composed of five named systems (Operations, Coordination, Intelligence, Governance,
|
|
72
86
|
Identity) plus an async runtime so many capsules can run concurrently.
|
|
73
|
-
|
|
74
|
-
Highlights
|
|
75
|
-
• Capsules & recursion: compose larger organisms from smaller capsules, each with its
|
|
76
|
-
own Operations/Coordination/Intelligence/Governance/Identity.
|
|
77
|
-
• Async runtime: fiber‑based (async gem) message bus and scheduler with “floor
|
|
78
|
-
control” per session; great for streaming output and multi‑turn tool loops.
|
|
79
|
-
• Tools as capsules: implement tools as first‑class capsules with JSON‑Schema
|
|
80
|
-
descriptors, ready to expose to OpenAI‑compatible function calling; adapters for
|
|
81
|
-
other providers (e.g., Anthropic/Gemini) fit the same interface.
|
|
82
|
-
• Parallel execution: pluggable executors (fiber/thread today) so tool calls can run
|
|
83
|
-
concurrently; swap in ractors/subprocess isolation later without API changes.
|
|
84
|
-
• Observability: append‑only JSONL event ledger; simple hooks to add tracing/metrics
|
|
85
|
-
so you can build a live “lens” UI or ship logs to your infra.
|
|
86
|
-
• Ports (ingress/egress): clean adapters for TTY/HTTP/MCP/etc. so multiple
|
|
87
|
-
interaction models can share the same organism.
|
|
88
|
-
|
|
89
|
-
Use cases
|
|
90
|
-
• CLI chat agents with streaming and native tool calling
|
|
91
|
-
• Editor/CI sub‑agents (planner, tester, refactorer) composed as capsules
|
|
92
|
-
• MCP tool hosts/clients and other integrator bots
|
|
93
|
-
|
|
94
|
-
Status: early but practical. APIs may evolve as we add more provider drivers and
|
|
95
|
-
ports, but the core Capsule/Systems abstractions should be stable.
|
|
96
87
|
email:
|
|
97
88
|
- scott@sublayer.com
|
|
98
|
-
executables:
|
|
89
|
+
executables:
|
|
90
|
+
- vsm
|
|
99
91
|
extensions: []
|
|
100
92
|
extra_rdoc_files: []
|
|
101
93
|
files:
|
|
94
|
+
- ".claude/settings.local.json"
|
|
102
95
|
- ".rspec"
|
|
103
|
-
-
|
|
96
|
+
- CLAUDE.md
|
|
104
97
|
- LICENSE.txt
|
|
105
98
|
- README.md
|
|
106
99
|
- Rakefile
|
|
100
|
+
- examples/01_echo_tool.rb
|
|
101
|
+
- examples/02_openai_streaming.rb
|
|
102
|
+
- examples/02b_anthropic_streaming.rb
|
|
103
|
+
- examples/02c_gemini_streaming.rb
|
|
104
|
+
- examples/03_openai_tools.rb
|
|
105
|
+
- examples/03b_anthropic_tools.rb
|
|
106
|
+
- examples/03c_gemini_tools.rb
|
|
107
|
+
- examples/05_mcp_server_and_chattty.rb
|
|
108
|
+
- examples/06_mcp_mount_reflection.rb
|
|
109
|
+
- examples/07_connect_claude_mcp.rb
|
|
110
|
+
- examples/08_custom_chattty.rb
|
|
111
|
+
- examples/09_mcp_with_llm_calls.rb
|
|
112
|
+
- examples/10_meta_read_only.rb
|
|
113
|
+
- exe/vsm
|
|
107
114
|
- lib/vsm.rb
|
|
115
|
+
- lib/vsm/async_channel.rb
|
|
116
|
+
- lib/vsm/capsule.rb
|
|
117
|
+
- lib/vsm/cli.rb
|
|
118
|
+
- lib/vsm/drivers/anthropic/async_driver.rb
|
|
119
|
+
- lib/vsm/drivers/family.rb
|
|
120
|
+
- lib/vsm/drivers/gemini/async_driver.rb
|
|
121
|
+
- lib/vsm/drivers/openai/async_driver.rb
|
|
122
|
+
- lib/vsm/dsl.rb
|
|
123
|
+
- lib/vsm/dsl_mcp.rb
|
|
124
|
+
- lib/vsm/executors/fiber_executor.rb
|
|
125
|
+
- lib/vsm/executors/thread_executor.rb
|
|
126
|
+
- lib/vsm/generator/new_project.rb
|
|
127
|
+
- lib/vsm/generator/templates/Gemfile.erb
|
|
128
|
+
- lib/vsm/generator/templates/README_md.erb
|
|
129
|
+
- lib/vsm/generator/templates/Rakefile.erb
|
|
130
|
+
- lib/vsm/generator/templates/bin_console.erb
|
|
131
|
+
- lib/vsm/generator/templates/bin_setup.erb
|
|
132
|
+
- lib/vsm/generator/templates/exe_name.erb
|
|
133
|
+
- lib/vsm/generator/templates/gemspec.erb
|
|
134
|
+
- lib/vsm/generator/templates/gitignore.erb
|
|
135
|
+
- lib/vsm/generator/templates/lib_name_rb.erb
|
|
136
|
+
- lib/vsm/generator/templates/lib_organism_rb.erb
|
|
137
|
+
- lib/vsm/generator/templates/lib_ports_chat_tty_rb.erb
|
|
138
|
+
- lib/vsm/generator/templates/lib_tools_read_file_rb.erb
|
|
139
|
+
- lib/vsm/generator/templates/lib_version_rb.erb
|
|
140
|
+
- lib/vsm/homeostat.rb
|
|
141
|
+
- lib/vsm/lens.rb
|
|
142
|
+
- lib/vsm/lens/event_hub.rb
|
|
143
|
+
- lib/vsm/lens/server.rb
|
|
144
|
+
- lib/vsm/lens/stats.rb
|
|
145
|
+
- lib/vsm/lens/tui.rb
|
|
146
|
+
- lib/vsm/mcp/client.rb
|
|
147
|
+
- lib/vsm/mcp/jsonrpc.rb
|
|
148
|
+
- lib/vsm/mcp/remote_tool_capsule.rb
|
|
149
|
+
- lib/vsm/message.rb
|
|
150
|
+
- lib/vsm/meta.rb
|
|
151
|
+
- lib/vsm/meta/snapshot_builder.rb
|
|
152
|
+
- lib/vsm/meta/snapshot_cache.rb
|
|
153
|
+
- lib/vsm/meta/support.rb
|
|
154
|
+
- lib/vsm/meta/tools.rb
|
|
155
|
+
- lib/vsm/observability/ledger.rb
|
|
156
|
+
- lib/vsm/port.rb
|
|
157
|
+
- lib/vsm/ports/chat_tty.rb
|
|
158
|
+
- lib/vsm/ports/mcp/server_stdio.rb
|
|
159
|
+
- lib/vsm/roles/coordination.rb
|
|
160
|
+
- lib/vsm/roles/governance.rb
|
|
161
|
+
- lib/vsm/roles/identity.rb
|
|
162
|
+
- lib/vsm/roles/intelligence.rb
|
|
163
|
+
- lib/vsm/roles/operations.rb
|
|
164
|
+
- lib/vsm/runtime.rb
|
|
165
|
+
- lib/vsm/tool/acts_as_tool.rb
|
|
166
|
+
- lib/vsm/tool/capsule.rb
|
|
167
|
+
- lib/vsm/tool/descriptor.rb
|
|
108
168
|
- lib/vsm/version.rb
|
|
169
|
+
- llms.txt
|
|
170
|
+
- mcp_update.md
|
|
109
171
|
- sig/vsm.rbs
|
|
110
172
|
homepage: https://github.com/sublayerapp/vsm
|
|
111
173
|
licenses:
|
|
@@ -120,14 +182,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
120
182
|
requirements:
|
|
121
183
|
- - ">="
|
|
122
184
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: '3.
|
|
185
|
+
version: '3.4'
|
|
124
186
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
187
|
requirements:
|
|
126
188
|
- - ">="
|
|
127
189
|
- !ruby/object:Gem::Version
|
|
128
190
|
version: '0'
|
|
129
191
|
requirements: []
|
|
130
|
-
rubygems_version: 3.
|
|
192
|
+
rubygems_version: 3.7.2
|
|
131
193
|
specification_version: 4
|
|
132
194
|
summary: 'Async, recursive agent framework for Ruby (Viable System Model): capsules,
|
|
133
195
|
tools-as-capsules, streaming tool calls, and observability.'
|