rails-agent-stack 0.2.3 → 0.2.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be409425a0ebe1936cbc02ec6720f47d5827423d5e4b362528e5c7033f2a6f1f
4
- data.tar.gz: fbbbb69a8a99544d9884793ab4863022e3430855e2bc059343193ae20e1d137b
3
+ metadata.gz: 20b490c75e044e2e9255dad04d19a5d4f91a3a3deacba5f2f5732c00df5ebd9c
4
+ data.tar.gz: fd73c3c31a38596cfb27be72e67d238c5c38d94a6b558e06c1a80f5d865460bc
5
5
  SHA512:
6
- metadata.gz: 5f9bfcf4579f2621ec45342a3549d4aafb58a503139773b4ec9a921eb85c759ed5f4aeb6acb7a4975fa3afce3dd56237450c9155216989a7e08abec19e2ad85b
7
- data.tar.gz: d93599b868b320d1e6f2c712edfad421815f5c3b5998bb52f7e6d6ee74fecfda420141a5ad52b984289f007372a29c60b36598aac03dccc91c2d711513a28d29
6
+ metadata.gz: 2976710722d70556f2f1cc44008e4ad57f2d31166d4135f7cc73561b43c47c567c178315a38287598bd3e57ccf3575664229456e1a56a272226e2930a1add108
7
+ data.tar.gz: 80a5e64548a04bce6df42211b01767c3604a6fe63a8de12e743ff967972ea7db762079029f283cd895722ac7a031558487c7dc4347e878aa326bda53c37465a5
data/AGENTS.md CHANGED
@@ -13,6 +13,6 @@ Quick start:
13
13
 
14
14
  Four taxonomy types: **Knowledge**, **Workflow**, **Operations**, **Monitoring**.
15
15
 
16
- Capabilities: **Tools**, **Skills**, **Packages** (Skills.sh / APM / Smithery), **Connectors**, **Knowledge**, plus workspace **Library** reuse.
16
+ Capabilities: **Tools**, **Skills**, **Packages** (Skills.sh / APM / Smithery), **Connectors**, **Knowledge**, plus `app/agents/shared/` reuse.
17
17
 
18
18
  Run responses: prefer `result.output_text` (Markdown) and optional `result.output_data` — see [docs/AGENTS.md](docs/AGENTS.md#run-response-schema-integrate-into-product) and https://rails-agent.com/docs/run-response.
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to `rails-agent-stack` will be documented in this file.
4
4
 
5
+ ## [0.2.4] - 2026-08-05
6
+
7
+ ### Changed
8
+
9
+ - Shared capabilities live under `app/agents/shared/` (one tree with agents).
10
+ Fresh installs no longer create sibling `app/agents_library/`.
11
+ - `imports.yml` prefers `from: shared/...`; legacy `from: library/...` and
12
+ existing `app/agents_library/` installs still resolve.
13
+ - Agent generator rejects reserved slugs `shared` and `library`.
14
+
5
15
  ## [0.2.3] - 2026-08-05
6
16
 
7
17
  ### Fixed
data/README.md CHANGED
@@ -80,7 +80,7 @@ Positioning in one line: **most advanced agentic platform for Ruby on Rails**
80
80
  | **Memory** | Conversation memory (Mem0-backed), on by default |
81
81
  | **Guardrails** | Model access, prompt injection, sensitive info |
82
82
  | **Playbooks** | Proven scaffolds you customize locally |
83
- | **Library** | Share tools, skills, packages, knowledge, connectors (`app/agents_library/` + `imports.yml`) |
83
+ | **Shared** | Share tools, skills, packages, knowledge, connectors (`app/agents/shared/` + `imports.yml`) |
84
84
 
85
85
  ### Test
86
86
 
@@ -141,7 +141,7 @@ Connect your company workspace at `/agents`, then scaffold a database Knowledge
141
141
  bin/rails generate rails_agents:agent store_assistant --type knowledge --database
142
142
  ```
143
143
 
144
- **Zeitwerk:** fresh installs add `config/initializers/rails_agents_autoload.rb` so `app/agents/` and `app/agents_library/` are agent assets, not application namespaces.
144
+ **Zeitwerk:** fresh installs add `config/initializers/rails_agents_autoload.rb` so `app/agents/` (including `shared/`) are agent assets, not application namespaces.
145
145
 
146
146
  External coding agents (Cursor, Claude Code, Codex): start with **[docs/AGENTS.md](docs/AGENTS.md)**.
147
147
 
@@ -178,7 +178,7 @@ end
178
178
  app/agents/store_assistant/
179
179
  ├── agent.rb # RailsAgents::KnowledgeAgent subclass
180
180
  ├── prompt.md # System prompt
181
- ├── imports.yml # Optional workspace Library attachments
181
+ ├── imports.yml # Optional shared attachments
182
182
  ├── tools/ # Optional extracted tools
183
183
  ├── skills/ # Composable behaviors
184
184
  ├── packages/ # Registry-installed capabilities
@@ -188,7 +188,7 @@ app/agents/store_assistant/
188
188
  ├── channels/ # Slack, Teams, web, API, …
189
189
  └── evals/ # Smoke / regression cases
190
190
 
191
- app/agents_library/
191
+ app/agents/shared/
192
192
  ├── tools/
193
193
  ├── skills/
194
194
  ├── packages/
@@ -196,7 +196,7 @@ app/agents_library/
196
196
  └── connectors/
197
197
  ```
198
198
 
199
- Keep one-off work inside the agent. Move stable capabilities to `app/agents_library/` when another agent should reuse them, then reference via `imports.yml`. `rails-agents sync` includes imported Library files in the runtime bundle without duplicating shared source in Git.
199
+ Keep one-off work inside the agent. Move stable capabilities to `app/agents/shared/` when another agent should reuse them, then reference via `imports.yml`. `rails-agents sync` includes imported shared files in the runtime bundle without duplicating shared source in Git.
200
200
 
201
201
  ---
202
202
 
data/docs/AGENTS.md CHANGED
@@ -97,13 +97,13 @@ Dashboard uses `GET /agents/schema` to discover tables for database setup — ke
97
97
  Add Ruby tool blocks in `agent.rb` or files under `tools/`. Tools run in your Rails app context.
98
98
  Start with one read-only tool and test it before adding side effects.
99
99
 
100
- ### Workspace Library (share only when reuse is real)
100
+ ### Workspace shared folder (reuse only when needed)
101
101
 
102
102
  Agent-specific capabilities stay under `app/agents/<slug>/`. Capabilities used
103
103
  by multiple agents have one canonical source under:
104
104
 
105
105
  ```text
106
- app/agents_library/
106
+ app/agents/shared/
107
107
  ├── tools/
108
108
  ├── skills/
109
109
  ├── packages/
@@ -118,20 +118,23 @@ version: 1
118
118
  imports:
119
119
  - kind: skill
120
120
  slug: triage
121
- from: library/skills/triage.rb
121
+ from: shared/skills/triage.rb
122
122
  - kind: knowledge
123
123
  slug: shipping_policy
124
- from: library/knowledge/shipping_policy.md
124
+ from: shared/knowledge/shipping_policy.md
125
125
  - kind: package
126
126
  slug: frontend_design
127
- from: library/packages/frontend_design
127
+ from: shared/packages/frontend_design
128
128
  ```
129
129
 
130
130
  `bundle exec rails-agents sync NAME` safely resolves these paths and includes
131
131
  them in the agent bundle. It fails on path traversal, missing sources, or a
132
- conflict with an agent-local file. This keeps the Library canonical without
132
+ conflict with an agent-local file. This keeps shared sources canonical without
133
133
  duplicating generated copies in Git.
134
134
 
135
+ Legacy installs may still use `app/agents_library/` and `from: library/...`;
136
+ both continue to resolve.
137
+
135
138
  Shared Ruby tool files are organization boundaries, not a new DSL. Register the
136
139
  tool in `agent.rb` using the normal `tool` block and call the shared module or
137
140
  service from that block.
@@ -8,6 +8,8 @@ module RailsAgents
8
8
  class AgentGenerator < Rails::Generators::NamedBase
9
9
  source_root File.expand_path("templates", __dir__)
10
10
 
11
+ RESERVED_SLUGS = %w[shared library].freeze
12
+
11
13
  class_option :type,
12
14
  type: :string,
13
15
  default: "knowledge",
@@ -21,6 +23,11 @@ module RailsAgents
21
23
  desc "Scaffold an agent directory under app/agents/"
22
24
 
23
25
  def create_agent_directory
26
+ if RESERVED_SLUGS.include?(file_name)
27
+ raise Thor::Error,
28
+ "Agent name #{file_name.inspect} is reserved for app/agents/shared/. Choose another name."
29
+ end
30
+
24
31
  empty_directory agent_path
25
32
  empty_directory File.join(agent_path, "tools")
26
33
  empty_directory File.join(agent_path, "skills")
@@ -5,38 +5,14 @@ class <%= class_name %> < RailsAgents::KnowledgeAgent
5
5
  memory :conversation
6
6
  knowledge_from "knowledge/**/*"
7
7
 
8
- tool :lookup_order do |order_number:|
9
- order = Order.find_by(number: order_number)
10
- return { error: "Order not found", order_number: order_number } unless order
11
-
12
- {
13
- number: order.number,
14
- status: order.status,
15
- customer_name: order.customer_name,
16
- customer_email: order.customer_email,
17
- total_cents: order.total_cents,
18
- currency: order.currency,
19
- shipped_at: order.shipped_at&.iso8601
20
- }
21
- end
22
-
23
- tool :search_products do |query:|
24
- scope = Product.where(status: "active")
25
- if query.present?
26
- pattern = "%#{query}%"
27
- scope = scope.where("name LIKE ? OR sku LIKE ?", pattern, pattern)
28
- end
29
-
30
- scope.limit(10).map do |product|
31
- {
32
- sku: product.sku,
33
- name: product.name,
34
- price_cents: product.price_cents,
35
- stock: product.stock,
36
- collection: product.collection&.name
37
- }
38
- end
39
- end
8
+ # Add tools when the workflow needs live Rails data, e.g.:
9
+ # tool :lookup_order do |order_number:|
10
+ # order = Order.find_by(number: order_number)
11
+ # ...
12
+ # end
13
+ # tool :search_products do |query:|
14
+ # Product.where(status: "active").limit(10)...
15
+ # end
40
16
 
41
17
  channel :web
42
18
  end
@@ -1,9 +1,9 @@
1
1
  version: 1
2
2
 
3
- # Reuse capabilities from app/agents_library without duplicating source files.
3
+ # Reuse capabilities from app/agents/shared without duplicating source files.
4
4
  # Example:
5
5
  # imports:
6
6
  # - kind: skill
7
7
  # slug: triage
8
- # from: library/skills/triage.rb
8
+ # from: shared/skills/triage.rb
9
9
  imports: []
@@ -1,14 +1,16 @@
1
- # <%= class_name %> Agent
1
+ # Customer Support Agent
2
+ You are a customer support agent that answers customer questions using customer information from the database.
2
3
 
3
- You are <%= class_name %>, a database-connected Knowledge agent for this Rails app.
4
+ ## Trigger - When the agent is invoked?
5
+ When a customer asks a question, we will invoke this agent to understand what they are asking and respond to it.
4
6
 
5
- ## Tools
6
-
7
- - `lookup_order(order_number:)` order status, customer, total, shipped_at
8
- - `search_products(query:)` active products by name or SKU
7
+ ## Workflow - What the agent executes?
8
+ 1. The agent will understand the question
9
+ 2. Ask followup questions if anything unclear
10
+ 3. If clear, it will go and search in the database and give an answer
9
11
 
10
- ## Demo data
12
+ ## Tools
11
13
 
12
- After `bin/rails db:seed`, try order numbers like `ORD-DEMO-1001` or ask about products such as "Classic Tee".
14
+ Add Rails tools under Tools when you need live lookups (for example `lookup_order` or `search_products`). Until a tool is written, the agent should say so instead of inventing data.
13
15
 
14
16
  Provider credentials live in Rails Agent Cloud (BYOK). Do not commit secrets to this repository.
@@ -22,12 +22,13 @@ module RailsAgents
22
22
  template "AGENTS.md.tt", "AGENTS.md"
23
23
  end
24
24
 
25
- def create_workspace_library
25
+ def create_agents_tree
26
+ empty_directory "app/agents"
26
27
  %w[tools skills connectors plugins knowledge knowledge/sources packages].each do |folder|
27
- empty_directory File.join("app/agents_library", folder)
28
+ empty_directory File.join("app/agents/shared", folder)
28
29
  end
29
- template "library_manifest.yml.tt", "app/agents_library/manifest.yml"
30
- template "library_README.md.tt", "app/agents_library/README.md"
30
+ template "library_manifest.yml.tt", "app/agents/shared/manifest.yml"
31
+ template "library_README.md.tt", "app/agents/shared/README.md"
31
32
  end
32
33
 
33
34
  def create_env_placeholders
@@ -31,10 +31,10 @@ Never commit provider API keys to this repository.
31
31
  ## Reusable capabilities
32
32
 
33
33
  Keep agent-specific files under `app/agents/<slug>/`. Put stable tools, skills,
34
- knowledge, or plugin manifests needed by multiple agents under
35
- `app/agents_library/`, then attach them through the agent's `imports.yml`.
34
+ knowledge, or connector manifests needed by multiple agents under
35
+ `app/agents/shared/`, then attach them through the agent's `imports.yml`.
36
36
 
37
- Do not move a capability into the Library until another agent needs it.
37
+ Do not move a capability into shared until another agent needs it.
38
38
 
39
39
  ## Taxonomy
40
40
 
@@ -1,6 +1,7 @@
1
- # Agent Library
1
+ # Shared agent capabilities
2
2
 
3
- Reusable capabilities shared by agents in this Rails application.
3
+ Reusable tools, skills, packages, knowledge, and connectors used by more than
4
+ one agent in this Rails app.
4
5
 
5
6
  - `tools/` — Ruby actions and service wrappers
6
7
  - `skills/` — reusable multi-step behavior
@@ -18,11 +19,14 @@ version: 1
18
19
  imports:
19
20
  - kind: skill
20
21
  slug: triage
21
- from: library/skills/triage.rb
22
+ from: shared/skills/triage.rb
22
23
  - kind: package
23
24
  slug: frontend_design
24
- from: library/packages/frontend_design
25
+ from: shared/packages/frontend_design
25
26
  ```
26
27
 
28
+ Legacy `from: library/...` paths still resolve to this folder (or to
29
+ `app/agents_library/` on older installs).
30
+
27
31
  `rails-agents sync <agent>` uploads imported files into that agent's runtime
28
32
  bundle without duplicating the shared source in the repository.
@@ -7,7 +7,9 @@ Rails.application.configure do
7
7
  config.before_configuration do
8
8
  if defined?(Rails.autoloaders) && Rails.autoloaders.respond_to?(:main) && Rails.autoloaders.main
9
9
  Rails.autoloaders.main.ignore(Rails.root.join("app/agents"))
10
- Rails.autoloaders.main.ignore(Rails.root.join("app/agents_library"))
10
+ # Legacy sibling path — still ignore if an older install kept it.
11
+ legacy = Rails.root.join("app/agents_library")
12
+ Rails.autoloaders.main.ignore(legacy) if legacy.exist?
11
13
  end
12
14
  end
13
15
  end
@@ -108,7 +108,7 @@ module RailsAgents
108
108
  )
109
109
 
110
110
  Client.new.sync_files(agent: name, files: files)
111
- suffix = imported.empty? ? "" : " (#{imported.size} from app/agents_library)"
111
+ suffix = imported.empty? ? "" : " (#{imported.size} from app/agents/shared)"
112
112
  say "Synced #{files.size} files for #{name}#{suffix}"
113
113
  rescue LibraryImports::Error => e
114
114
  say_error e.message
@@ -5,8 +5,9 @@ require "yaml"
5
5
 
6
6
  module RailsAgents
7
7
  # Resolves workspace-shared capabilities declared by an agent's imports.yml.
8
- # Sources live under app/agents_library; sync uploads virtual agent-local
9
- # copies so the cloud runtime keeps its existing app/agents/<slug>/ contract.
8
+ # Sources live under app/agents/shared (preferred) or legacy app/agents_library.
9
+ # Sync uploads virtual agent-local copies so the cloud runtime keeps its
10
+ # existing app/agents/<slug>/ contract.
10
11
  class LibraryImports
11
12
  class Error < StandardError; end
12
13
 
@@ -21,6 +22,9 @@ module RailsAgents
21
22
  "knowledge" => ".md",
22
23
  "package" => ".yml"
23
24
  }.freeze
25
+ # Logical import prefixes → physical shared root (app/agents/shared).
26
+ # "library/" kept for backwards-compatible imports.yml files.
27
+ FROM_PREFIXES = %w[shared/ library/].freeze
24
28
 
25
29
  attr_reader :agent_directory, :library_root
26
30
 
@@ -43,12 +47,12 @@ module RailsAgents
43
47
 
44
48
  def virtual_files
45
49
  entries.flat_map do |entry|
46
- raise Error, "Missing Library source: #{entry.source}" unless entry.source.exist?
50
+ raise Error, "Missing shared source: #{entry.source}" unless entry.source.exist?
47
51
 
48
52
  if entry.kind == "package"
49
53
  package_virtual_files(entry)
50
54
  else
51
- raise Error, "Missing Library source: #{entry.source}" unless entry.source.file?
55
+ raise Error, "Missing shared source: #{entry.source}" unless entry.source.file?
52
56
 
53
57
  [{
54
58
  "path" => cloud_path(entry.target),
@@ -63,6 +67,17 @@ module RailsAgents
63
67
  entries.select { |entry| entry.kind == "knowledge" }.map { |entry| entry.target.to_s }
64
68
  end
65
69
 
70
+ def self.resolve_library_root(agents_root)
71
+ agents_root = Pathname.new(agents_root)
72
+ shared = agents_root.join("shared")
73
+ return shared if shared.exist?
74
+
75
+ legacy = agents_root.parent.join("agents_library")
76
+ return legacy if legacy.exist?
77
+
78
+ shared
79
+ end
80
+
66
81
  private
67
82
 
68
83
  def package_virtual_files(entry)
@@ -74,7 +89,7 @@ module RailsAgents
74
89
  else
75
90
  entry.source
76
91
  end
77
- raise Error, "Missing Library package directory: #{root}" unless root.directory?
92
+ raise Error, "Missing shared package directory: #{root}" unless root.directory?
78
93
 
79
94
  Dir.glob(root.join("**", "*").to_s).select { |path| File.file?(path) }.map do |path|
80
95
  file = Pathname.new(path)
@@ -93,7 +108,7 @@ module RailsAgents
93
108
  end
94
109
 
95
110
  def default_library_root
96
- agent_directory.parent.parent.join("agents_library")
111
+ self.class.resolve_library_root(agent_directory.parent)
97
112
  end
98
113
 
99
114
  def build_entry(raw)
@@ -102,12 +117,15 @@ module RailsAgents
102
117
  kind = raw["kind"].to_s
103
118
  kind = "connector" if kind == "plugin"
104
119
  slug = normalize_slug(raw["slug"])
105
- raise Error, "Unsupported Library kind: #{kind.inspect}" unless KINDS.include?(kind)
106
- raise Error, "Library import slug is required" if slug.empty?
120
+ raise Error, "Unsupported shared kind: #{kind.inspect}" unless KINDS.include?(kind)
121
+ raise Error, "Shared import slug is required" if slug.empty?
107
122
 
108
123
  from = raw["from"].to_s
109
- prefix = "library/"
110
- raise Error, "Library import #{slug} must use from: library/..." unless from.start_with?(prefix)
124
+ prefix = FROM_PREFIXES.find { |p| from.start_with?(p) }
125
+ unless prefix
126
+ raise Error,
127
+ "Shared import #{slug} must use from: shared/... (or legacy library/...)"
128
+ end
111
129
 
112
130
  source_relative = safe_relative(from.delete_prefix(prefix), "source")
113
131
  source = library_root.join(source_relative)
@@ -131,7 +149,7 @@ module RailsAgents
131
149
  path = Pathname.new(value)
132
150
  clean = path.cleanpath
133
151
  if path.absolute? || clean.to_s == ".." || clean.to_s.start_with?("../")
134
- raise Error, "Library import #{label} must stay inside its root"
152
+ raise Error, "Shared import #{label} must stay inside its root"
135
153
  end
136
154
  clean
137
155
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsAgents
4
- VERSION = "0.2.3"
4
+ VERSION = "0.2.4"
5
5
  end
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.description = <<~DESC
15
15
  Rails Agent is a single, beautiful full-stack agentic platform for Ruby on Rails. Build chatbots, knowledge (RAG-style) agents, workflow agents, operations jobs, monitoring agents, and every agentic workflow you can think of — as files in app/agents/, with a mounted /agents dashboard and hosted cloud runtime.
16
16
 
17
- Build: instructions (prompt.md), tools (function calling over ActiveRecord), connectors (OAuth SaaS), channels (Slack, Teams via Open-Wire, web, cron, HTTP API), skills, packages (Skills.sh / APM / Smithery), knowledge, memory (Mem0), guardrails, playbooks, and a shared agents library.
17
+ Build: instructions (prompt.md), tools (function calling over ActiveRecord), connectors (OAuth SaaS), channels (Slack, Teams via Open-Wire, web, cron, HTTP API), skills, packages (Skills.sh / APM / Smithery), knowledge, memory (Mem0), guardrails, playbooks, and app/agents/shared for reusable capabilities.
18
18
 
19
19
  Test: cloud sandbox runs, streaming, evals (golden cases), traces, and cost before you ship.
20
20
 
@@ -12,18 +12,19 @@ RSpec.describe "Agent generator templates" do
12
12
  expect(content).not_to include("model :auto")
13
13
  end
14
14
 
15
- it "database template scaffolds KnowledgeAgent with order and product tools" do
16
- content = File.read(File.join(templates_root, "agent_database.rb.tt"))
15
+ it "database template scaffolds KnowledgeAgent without binding default tools" do
16
+ content = File.read(File.join(templates_root, "agent_database.rb.tt"), encoding: "UTF-8")
17
17
  expect(content).to include("KnowledgeAgent")
18
- expect(content).to include("lookup_order")
19
- expect(content).to include("search_products")
20
- expect(content).to include("Order.find_by")
21
- expect(content).to include("Product.where")
18
+ expect(content).to include("Add tools when the workflow needs live Rails data")
19
+ expect(content).not_to match(/^\s*tool :lookup_order/m)
20
+ expect(content).not_to match(/^\s*tool :search_products/m)
22
21
  end
23
22
 
24
- it "database prompt documents demo orders and BYOK" do
23
+ it "database prompt documents support triage workflow and BYOK" do
25
24
  content = File.read(File.join(templates_root, "prompt_database.md.tt"))
26
- expect(content).to include("ORD-DEMO-1001")
25
+ expect(content).to include("Customer Support Agent")
26
+ expect(content).to include("Ask followup questions if anything unclear")
27
+ expect(content).to include("Until a tool is written")
27
28
  expect(content).to include("BYOK")
28
29
  end
29
30
 
@@ -31,6 +32,6 @@ RSpec.describe "Agent generator templates" do
31
32
  content = File.read(File.join(templates_root, "imports.yml.tt"))
32
33
 
33
34
  expect(content).to include("imports: []")
34
- expect(content).to include("library/skills/triage.rb")
35
+ expect(content).to include("shared/skills/triage.rb")
35
36
  end
36
37
  end
@@ -9,22 +9,22 @@ RSpec.describe RailsAgents::LibraryImports do
9
9
  Dir.mktmpdir do |root|
10
10
  @root = Pathname.new(root)
11
11
  @agent_dir = @root.join("app/agents/support")
12
- @library_dir = @root.join("app/agents_library")
12
+ @shared_dir = @root.join("app/agents/shared")
13
13
  FileUtils.mkdir_p(@agent_dir)
14
- FileUtils.mkdir_p(@library_dir)
14
+ FileUtils.mkdir_p(@shared_dir)
15
15
  example.run
16
16
  end
17
17
  end
18
18
 
19
- it "builds virtual agent files from shared Library imports" do
20
- FileUtils.mkdir_p(@library_dir.join("skills"))
21
- @library_dir.join("skills/triage.rb").write("module Triage; end\n")
19
+ it "builds virtual agent files from app/agents/shared imports" do
20
+ FileUtils.mkdir_p(@shared_dir.join("skills"))
21
+ @shared_dir.join("skills/triage.rb").write("module Triage; end\n")
22
22
  @agent_dir.join("imports.yml").write(<<~YAML)
23
23
  version: 1
24
24
  imports:
25
25
  - kind: skill
26
26
  slug: triage
27
- from: library/skills/triage.rb
27
+ from: shared/skills/triage.rb
28
28
  YAML
29
29
 
30
30
  files = described_class.new(@agent_dir).virtual_files
@@ -38,15 +38,33 @@ RSpec.describe RailsAgents::LibraryImports do
38
38
  )
39
39
  end
40
40
 
41
+ it "still resolves legacy from: library/ and app/agents_library/" do
42
+ legacy = @root.join("app/agents_library")
43
+ FileUtils.rm_rf(@shared_dir)
44
+ FileUtils.mkdir_p(legacy.join("skills"))
45
+ legacy.join("skills/triage.rb").write("module Triage; end\n")
46
+ @agent_dir.join("imports.yml").write(<<~YAML)
47
+ version: 1
48
+ imports:
49
+ - kind: skill
50
+ slug: triage
51
+ from: library/skills/triage.rb
52
+ YAML
53
+
54
+ files = described_class.new(@agent_dir).virtual_files
55
+
56
+ expect(files.first["path"]).to eq("app/agents/support/skills/triage.rb")
57
+ end
58
+
41
59
  it "exposes imported knowledge at its agent-relative runtime path" do
42
- FileUtils.mkdir_p(@library_dir.join("knowledge"))
43
- @library_dir.join("knowledge/policy.md").write("# Policy\n")
60
+ FileUtils.mkdir_p(@shared_dir.join("knowledge"))
61
+ @shared_dir.join("knowledge/policy.md").write("# Policy\n")
44
62
  @agent_dir.join("imports.yml").write(<<~YAML)
45
63
  version: 1
46
64
  imports:
47
65
  - kind: knowledge
48
66
  slug: policy
49
- from: library/knowledge/policy.md
67
+ from: shared/knowledge/policy.md
50
68
  as: knowledge/company/policy.md
51
69
  YAML
52
70
 
@@ -58,13 +76,13 @@ RSpec.describe RailsAgents::LibraryImports do
58
76
  )
59
77
  end
60
78
 
61
- it "rejects paths that escape the Library" do
79
+ it "rejects paths that escape the shared root" do
62
80
  @agent_dir.join("imports.yml").write(<<~YAML)
63
81
  version: 1
64
82
  imports:
65
83
  - kind: tool
66
84
  slug: secret
67
- from: library/../../config/master.key
85
+ from: shared/../../config/master.key
68
86
  YAML
69
87
 
70
88
  expect { described_class.new(@agent_dir).entries }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-agent-stack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiny Bubble Company
@@ -97,7 +97,7 @@ dependencies:
97
97
  description: |
98
98
  Rails Agent is a single, beautiful full-stack agentic platform for Ruby on Rails. Build chatbots, knowledge (RAG-style) agents, workflow agents, operations jobs, monitoring agents, and every agentic workflow you can think of — as files in app/agents/, with a mounted /agents dashboard and hosted cloud runtime.
99
99
 
100
- Build: instructions (prompt.md), tools (function calling over ActiveRecord), connectors (OAuth SaaS), channels (Slack, Teams via Open-Wire, web, cron, HTTP API), skills, packages (Skills.sh / APM / Smithery), knowledge, memory (Mem0), guardrails, playbooks, and a shared agents library.
100
+ Build: instructions (prompt.md), tools (function calling over ActiveRecord), connectors (OAuth SaaS), channels (Slack, Teams via Open-Wire, web, cron, HTTP API), skills, packages (Skills.sh / APM / Smithery), knowledge, memory (Mem0), guardrails, playbooks, and app/agents/shared for reusable capabilities.
101
101
 
102
102
  Test: cloud sandbox runs, streaming, evals (golden cases), traces, and cost before you ship.
103
103