rails-agent-stack 0.1.1

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 (91) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/README.md +16 -0
  3. data/.github/workflows/ci.yml +32 -0
  4. data/.gitignore +8 -0
  5. data/.rspec +3 -0
  6. data/AGENTS.md +18 -0
  7. data/CHANGELOG.md +40 -0
  8. data/Gemfile +15 -0
  9. data/MIT-LICENSE +21 -0
  10. data/README.md +228 -0
  11. data/Rakefile +8 -0
  12. data/app/assets/images/rails_agents/kip-logo.png +0 -0
  13. data/app/assets/images/rails_agents/kip-waving.png +0 -0
  14. data/app/assets/stylesheets/rails_agents/application.css +411 -0
  15. data/app/controllers/rails_agents/application_controller.rb +25 -0
  16. data/app/controllers/rails_agents/connect_controller.rb +36 -0
  17. data/app/controllers/rails_agents/dashboard_controller.rb +70 -0
  18. data/app/controllers/rails_agents/handshake_controller.rb +55 -0
  19. data/app/controllers/rails_agents/open_wire_inbound_controller.rb +153 -0
  20. data/app/controllers/rails_agents/pulls_controller.rb +42 -0
  21. data/app/controllers/rails_agents/registrations_controller.rb +96 -0
  22. data/app/controllers/rails_agents/schema_controller.rb +123 -0
  23. data/app/controllers/rails_agents/sessions_controller.rb +76 -0
  24. data/app/controllers/rails_agents/tool_bridge_controller.rb +67 -0
  25. data/app/views/layouts/rails_agents/application.html.erb +18 -0
  26. data/app/views/rails_agents/dashboard/show.html.erb +139 -0
  27. data/app/views/rails_agents/registrations/new.html.erb +83 -0
  28. data/app/views/rails_agents/sessions/new.html.erb +73 -0
  29. data/app/views/rails_agents/shared/_auth_brand.html.erb +20 -0
  30. data/config/routes.rb +34 -0
  31. data/docs/AGENTS.md +220 -0
  32. data/docs/PRD.md +89 -0
  33. data/docs/assets/hero-banner.png +0 -0
  34. data/examples/support/agent.rb +14 -0
  35. data/examples/support/channels/.keep +0 -0
  36. data/examples/support/evals/smoke.yml +4 -0
  37. data/examples/support/knowledge/shipping.md +1 -0
  38. data/examples/support/memory.rb +3 -0
  39. data/examples/support/prompt.md +9 -0
  40. data/examples/support/skills/.keep +0 -0
  41. data/examples/support/tools/.keep +0 -0
  42. data/exe/rails-agents +6 -0
  43. data/lib/generators/rails_agents/agent/agent_generator.rb +80 -0
  44. data/lib/generators/rails_agents/agent/templates/agent.rb.tt +14 -0
  45. data/lib/generators/rails_agents/agent/templates/agent_database.rb.tt +42 -0
  46. data/lib/generators/rails_agents/agent/templates/channels/slack.rb.tt +8 -0
  47. data/lib/generators/rails_agents/agent/templates/evals/smoke.yml.tt +4 -0
  48. data/lib/generators/rails_agents/agent/templates/imports.yml.tt +9 -0
  49. data/lib/generators/rails_agents/agent/templates/memory.rb.tt +6 -0
  50. data/lib/generators/rails_agents/agent/templates/prompt.md.tt +10 -0
  51. data/lib/generators/rails_agents/agent/templates/prompt_database.md.tt +14 -0
  52. data/lib/generators/rails_agents/install/INSTALL +10 -0
  53. data/lib/generators/rails_agents/install/install_generator.rb +72 -0
  54. data/lib/generators/rails_agents/install/templates/AGENTS.md.tt +46 -0
  55. data/lib/generators/rails_agents/install/templates/initializer.rb.tt +8 -0
  56. data/lib/generators/rails_agents/install/templates/library_README.md.tt +28 -0
  57. data/lib/generators/rails_agents/install/templates/library_manifest.yml.tt +5 -0
  58. data/lib/generators/rails_agents/install/templates/rails_agents_autoload.rb.tt +10 -0
  59. data/lib/rails-agent-stack.rb +4 -0
  60. data/lib/rails_agents/background_agent.rb +15 -0
  61. data/lib/rails_agents/base.rb +294 -0
  62. data/lib/rails_agents/chat_agent.rb +15 -0
  63. data/lib/rails_agents/cli.rb +245 -0
  64. data/lib/rails_agents/client.rb +216 -0
  65. data/lib/rails_agents/configuration.rb +41 -0
  66. data/lib/rails_agents/creation_agent.rb +10 -0
  67. data/lib/rails_agents/credentials_writer.rb +38 -0
  68. data/lib/rails_agents/engine.rb +19 -0
  69. data/lib/rails_agents/knowledge_agent.rb +10 -0
  70. data/lib/rails_agents/library_imports.rb +163 -0
  71. data/lib/rails_agents/local_auth.rb +56 -0
  72. data/lib/rails_agents/local_sync.rb +113 -0
  73. data/lib/rails_agents/monitoring_agent.rb +10 -0
  74. data/lib/rails_agents/open_wire_adapter.rb +31 -0
  75. data/lib/rails_agents/operations_agent.rb +10 -0
  76. data/lib/rails_agents/railtie.rb +14 -0
  77. data/lib/rails_agents/tasks.rake +8 -0
  78. data/lib/rails_agents/version.rb +5 -0
  79. data/lib/rails_agents/workflow_agent.rb +11 -0
  80. data/lib/rails_agents.rb +57 -0
  81. data/rails-agent-stack.gemspec +49 -0
  82. data/rails-agents.code-workspace +25 -0
  83. data/spec/generators/agent_generator_spec.rb +36 -0
  84. data/spec/rails_agents/base_spec.rb +202 -0
  85. data/spec/rails_agents/client_spec.rb +121 -0
  86. data/spec/rails_agents/configuration_spec.rb +55 -0
  87. data/spec/rails_agents/library_imports_spec.rb +80 -0
  88. data/spec/rails_agents/local_sync_spec.rb +63 -0
  89. data/spec/rails_agents/taxonomy_spec.rb +52 -0
  90. data/spec/spec_helper.rb +27 -0
  91. metadata +229 -0
@@ -0,0 +1,139 @@
1
+ <div class="rails-agents-embed-shell">
2
+ <span id="rails-agents-sync-status" class="rails-agents-sync-status rails-agents-sync-status--sr" aria-live="polite"></span>
3
+ <iframe
4
+ id="rails-agents-dashboard-frame"
5
+ class="rails-agents-embed"
6
+ src="<%= @dashboard_url %>"
7
+ title="Agents dashboard"
8
+ allow="clipboard-write"
9
+ ></iframe>
10
+ </div>
11
+
12
+ <script>
13
+ (function () {
14
+ var SCHEMA_URL = <%= raw rails_agents.schema_path.to_json %>;
15
+ var DASHBOARD_PATH = <%= raw rails_agents.dashboard_path.to_json %>;
16
+ var frame = document.getElementById("rails-agents-dashboard-frame");
17
+ var cloudOrigin = frame ? new URL(frame.src).origin : null;
18
+ var CSRF = document.querySelector('meta[name="csrf-token"]');
19
+ var statusEl = document.getElementById("rails-agents-sync-status");
20
+ var ALLOWED = {
21
+ "https://cloud.rails-agent.com": true,
22
+ "https://rails-agent.com": true,
23
+ "http://localhost:3000": true,
24
+ "http://127.0.0.1:3000": true,
25
+ "http://localhost:3001": true,
26
+ "http://127.0.0.1:3001": true,
27
+ "http://localhost:8080": true,
28
+ "http://127.0.0.1:8080": true
29
+ };
30
+
31
+ function setStatus(text, isError) {
32
+ if (!statusEl) return;
33
+ statusEl.textContent = text || "";
34
+ statusEl.classList.toggle("rails-agents-sync-status--error", !!isError);
35
+ }
36
+
37
+ function headers() {
38
+ var h = {
39
+ "Accept": "application/json",
40
+ "Content-Type": "application/json"
41
+ };
42
+ if (CSRF) h["X-CSRF-Token"] = CSRF.getAttribute("content");
43
+ return h;
44
+ }
45
+
46
+ async function fetchSchema() {
47
+ var res = await fetch(SCHEMA_URL, {
48
+ method: "GET",
49
+ credentials: "same-origin",
50
+ headers: headers()
51
+ });
52
+ var json = {};
53
+ try { json = await res.json(); } catch (e) { json = {}; }
54
+ if (!res.ok || json.ok === false) {
55
+ throw new Error(json.error || ("Schema failed (" + res.status + ")"));
56
+ }
57
+ return json;
58
+ }
59
+
60
+ function syncBrowserUrl(data) {
61
+ if (!data.path || data.path.indexOf("/dashboard") !== 0) return;
62
+ var suffix = data.path.slice("/dashboard".length);
63
+ var next = DASHBOARD_PATH + suffix;
64
+ if (data.search) next += "?" + data.search;
65
+ if (data.hash) next += data.hash;
66
+ var current = window.location.pathname + window.location.search + window.location.hash;
67
+ if (next !== current) {
68
+ window.history.replaceState({ railsAgentsDashboard: true }, "", next);
69
+ }
70
+ }
71
+
72
+ function syncFrameFromBrowser() {
73
+ if (!frame || !frame.contentWindow || !cloudOrigin) return;
74
+ if (window.location.pathname.indexOf(DASHBOARD_PATH) !== 0) return;
75
+ var suffix = window.location.pathname.slice(DASHBOARD_PATH.length);
76
+ frame.contentWindow.postMessage({
77
+ type: "rails-agents:navigate-to",
78
+ path: "/dashboard" + suffix,
79
+ search: window.location.search.replace(/^\?/, ""),
80
+ hash: window.location.hash
81
+ }, cloudOrigin);
82
+ }
83
+
84
+ window.addEventListener("popstate", syncFrameFromBrowser);
85
+
86
+ window.addEventListener("message", function (event) {
87
+ if (!ALLOWED[event.origin]) return;
88
+ var data = event.data || {};
89
+
90
+ if (data.type === "rails-agents:navigate") {
91
+ syncBrowserUrl(data);
92
+ return;
93
+ }
94
+
95
+ if (data.type === "rails-agents:schema") {
96
+ fetchSchema()
97
+ .then(function (result) {
98
+ if (event.source && event.source.postMessage) {
99
+ event.source.postMessage({
100
+ type: "rails-agents:schema-result",
101
+ requestId: data.requestId,
102
+ ok: true,
103
+ tables: result.tables || [],
104
+ adapter: result.adapter,
105
+ databases: result.databases || [],
106
+ configFiles: result.config_files || []
107
+ }, event.origin);
108
+ }
109
+ })
110
+ .catch(function (err) {
111
+ if (event.source && event.source.postMessage) {
112
+ event.source.postMessage({
113
+ type: "rails-agents:schema-result",
114
+ requestId: data.requestId,
115
+ ok: false,
116
+ error: err.message || "Schema failed",
117
+ tables: []
118
+ }, event.origin);
119
+ }
120
+ });
121
+ return;
122
+ }
123
+
124
+ // Deprecated: cloud-to-local authoring pull. Use `rails-agents sync` (local → cloud)
125
+ // or scaffold agents with `rails generate rails_agents:agent`. See AGENTS.md.
126
+ if (data.type === "rails-agents:pull") {
127
+ if (event.source && event.source.postMessage) {
128
+ event.source.postMessage({
129
+ type: "rails-agents:pull-result",
130
+ requestId: data.requestId,
131
+ ok: false,
132
+ error: "Cloud pull is deprecated. Build agents locally (see AGENTS.md) and run rails-agents sync."
133
+ }, event.origin);
134
+ }
135
+ setStatus("Cloud pull deprecated — edit app/agents/ locally", true);
136
+ }
137
+ });
138
+ })();
139
+ </script>
@@ -0,0 +1,83 @@
1
+ <%
2
+ @step ||= :email
3
+ @workspace ||= (Rails.application.class.module_parent_name rescue "MyApp")
4
+ @github_url ||= "#"
5
+ %>
6
+ <div class="rails-agents-connect">
7
+ <%= render "rails_agents/shared/auth_brand" %>
8
+
9
+ <section class="rails-agents-connect__form-pane">
10
+ <div class="rails-agents-connect__card">
11
+ <% if notice.present? %>
12
+ <div class="rails-agents-flash"><%= notice %></div>
13
+ <% end %>
14
+ <% if alert.present? %>
15
+ <div class="rails-agents-flash rails-agents-flash--alert"><%= alert %></div>
16
+ <% end %>
17
+
18
+ <h2>Create workspace</h2>
19
+ <p class="rails-agents-lede">
20
+ Links this Rails app to your company workspace — build agents in
21
+ <code>app/agents/</code>, attach BYOK credentials in the cloud dashboard.
22
+ </p>
23
+
24
+ <% if @step.to_sym == :code %>
25
+ <p class="rails-agents-muted" style="margin-top:1.25rem">
26
+ Enter the code we sent to <strong><%= @email %></strong>
27
+ </p>
28
+ <% if @dev_code.present? %>
29
+ <p class="rails-agents-flash" style="margin-top:0.75rem">
30
+ Dev code: <code><%= @dev_code %></code>
31
+ </p>
32
+ <% end %>
33
+
34
+ <%= form_with url: rails_agents.signup_verify_path, method: :post, local: true, class: "rails-agents-form", html: { style: "margin-top:1rem" } do %>
35
+ <label>
36
+ Code
37
+ <input type="text" name="code" inputmode="numeric" pattern="\d{4}" maxlength="4" required autofocus autocomplete="one-time-code" placeholder="0000" />
38
+ </label>
39
+ <button type="submit" class="rails-agents-btn rails-agents-btn--primary">
40
+ Verify &amp; connect →
41
+ </button>
42
+ <% end %>
43
+
44
+ <p class="rails-agents-connect__foot">
45
+ <%= link_to "Use a different email", rails_agents.signup_path %>
46
+ </p>
47
+ <% else %>
48
+ <a class="rails-agents-btn rails-agents-btn--ghost rails-agents-btn--spaced"
49
+ href="<%= @github_url %>">
50
+ <svg class="rails-agents-github-icon" viewBox="0 0 16 16" aria-hidden="true">
51
+ <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
52
+ </svg>
53
+ Continue with GitHub
54
+ </a>
55
+
56
+ <div class="rails-agents-divider">or email</div>
57
+
58
+ <%= form_with url: rails_agents.signup_path, method: :post, local: true, class: "rails-agents-form" do %>
59
+ <label>
60
+ Workspace
61
+ <input type="text" name="workspace" value="<%= @workspace %>" autocomplete="organization" />
62
+ </label>
63
+ <label>
64
+ Your name <span>(optional)</span>
65
+ <input type="text" name="name" value="<%= @name %>" autocomplete="name" />
66
+ </label>
67
+ <label>
68
+ Email
69
+ <input type="email" name="email" value="<%= @email %>" required autocomplete="email" placeholder="you@company.com" />
70
+ </label>
71
+ <button type="submit" class="rails-agents-btn rails-agents-btn--primary">
72
+ Continue with email
73
+ </button>
74
+ <% end %>
75
+
76
+ <p class="rails-agents-connect__foot">
77
+ Already have an account?
78
+ <%= link_to "Sign in", rails_agents.signin_path %>
79
+ </p>
80
+ <% end %>
81
+ </div>
82
+ </section>
83
+ </div>
@@ -0,0 +1,73 @@
1
+ <%
2
+ @step ||= :email
3
+ @github_url ||= "#"
4
+ %>
5
+ <div class="rails-agents-connect">
6
+ <%= render "rails_agents/shared/auth_brand" %>
7
+
8
+ <section class="rails-agents-connect__form-pane">
9
+ <div class="rails-agents-connect__card">
10
+ <% if notice.present? %>
11
+ <div class="rails-agents-flash"><%= notice %></div>
12
+ <% end %>
13
+ <% if alert.present? %>
14
+ <div class="rails-agents-flash rails-agents-flash--alert"><%= alert %></div>
15
+ <% end %>
16
+
17
+ <h2>Sign in</h2>
18
+ <p class="rails-agents-lede">
19
+ Jump back into your workspace — nothing to reinstall.
20
+ </p>
21
+
22
+ <% if @step.to_sym == :code %>
23
+ <p class="rails-agents-muted" style="margin-top:1.25rem">
24
+ Enter the code we sent to <strong><%= @email %></strong>
25
+ </p>
26
+ <% if @dev_code.present? %>
27
+ <p class="rails-agents-flash" style="margin-top:0.75rem">
28
+ Dev code: <code><%= @dev_code %></code>
29
+ </p>
30
+ <% end %>
31
+
32
+ <%= form_with url: rails_agents.signin_verify_path, method: :post, local: true, class: "rails-agents-form", html: { style: "margin-top:1rem" } do %>
33
+ <label>
34
+ Code
35
+ <input type="text" name="code" inputmode="numeric" pattern="\d{4}" maxlength="4" required autofocus autocomplete="one-time-code" placeholder="0000" />
36
+ </label>
37
+ <button type="submit" class="rails-agents-btn rails-agents-btn--primary">
38
+ Verify &amp; connect →
39
+ </button>
40
+ <% end %>
41
+
42
+ <p class="rails-agents-connect__foot">
43
+ <%= link_to "Use a different email", rails_agents.signin_path %>
44
+ </p>
45
+ <% else %>
46
+ <a class="rails-agents-btn rails-agents-btn--ghost rails-agents-btn--spaced"
47
+ href="<%= @github_url %>">
48
+ <svg class="rails-agents-github-icon" viewBox="0 0 16 16" aria-hidden="true">
49
+ <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
50
+ </svg>
51
+ Continue with GitHub
52
+ </a>
53
+
54
+ <div class="rails-agents-divider">or email</div>
55
+
56
+ <%= form_with url: rails_agents.signin_path, method: :post, local: true, class: "rails-agents-form" do %>
57
+ <label>
58
+ Email
59
+ <input type="email" name="email" value="<%= @email %>" required autocomplete="email" placeholder="you@company.com" />
60
+ </label>
61
+ <button type="submit" class="rails-agents-btn rails-agents-btn--primary">
62
+ Continue with email
63
+ </button>
64
+ <% end %>
65
+
66
+ <p class="rails-agents-connect__foot">
67
+ New here?
68
+ <%= link_to "Create workspace", rails_agents.signup_path %>
69
+ </p>
70
+ <% end %>
71
+ </div>
72
+ </section>
73
+ </div>
@@ -0,0 +1,20 @@
1
+ <aside class="rails-agents-connect__brand">
2
+ <a class="rails-agents-logo-lockup" href="https://rails-agent.com" target="_blank" rel="noopener">
3
+ <span class="rails-agents-logo-mark" aria-hidden="true">RA</span>
4
+ <span class="rails-agents-logo-word">Rails <em>Agent</em></span>
5
+ </a>
6
+
7
+ <div class="rails-agents-connect__copy">
8
+ <h1>Fullstack agents for <em>Rails</em>.</h1>
9
+ <p>
10
+ Connect your company workspace, build agents in <code>app/agents/</code>
11
+ with your editor or external coding agent, then test, deploy, and monitor at
12
+ <code>/agents</code>.
13
+ </p>
14
+ <p class="rails-agents-muted">
15
+ Start with <strong>AGENTS.md</strong> in your repo — first step: a database Knowledge agent.
16
+ </p>
17
+ </div>
18
+
19
+ <p class="rails-agents-connect__meta">rails-agent.com</p>
20
+ </aside>
data/config/routes.rb ADDED
@@ -0,0 +1,34 @@
1
+ RailsAgents::Engine.routes.draw do
2
+ # First-run default: create workspace. Already connected → signup redirects to dashboard.
3
+ root to: "registrations#new"
4
+
5
+ get "signup", to: "registrations#new", as: :signup
6
+ post "signup", to: "registrations#create"
7
+ post "signup/verify", to: "registrations#verify", as: :signup_verify
8
+
9
+ get "signin", to: "sessions#new", as: :signin
10
+ post "signin", to: "sessions#create"
11
+ post "signin/verify", to: "sessions#verify", as: :signin_verify
12
+ delete "signout", to: "sessions#destroy", as: :signout
13
+
14
+ post "handshake", to: "handshake#create", as: :handshake
15
+ get "connect", to: "connect#show", as: :connect
16
+
17
+ # Deprecated compatibility: cloud-to-local pull (prefer local scaffold + `rails-agents sync`)
18
+ post "pull", to: "pulls#create", as: :pull
19
+
20
+ # ActiveRecord schema for Knowledge agents / database connector in dashboard
21
+ get "schema", to: "schema#show", as: :schema
22
+
23
+ # Production runtime → Rails tool execution. The bearer token is
24
+ # introspected against Rails Agent Cloud before any local code runs.
25
+ post "bridge/:agent/tools/:tool", to: "tool_bridge#create", as: :tool_bridge
26
+
27
+ # Open-Wire reverse path (channel → agent). No separate OpenWire::Engine mount.
28
+ # Gateway POSTs message.inbound here; gem open-wire verifies + parses.
29
+ post "open_wire/inbound", to: "open_wire_inbound#create", as: :open_wire_inbound
30
+ post "open_wire/inbound/:agent", to: "open_wire_inbound#create", as: :open_wire_inbound_agent
31
+
32
+ get "dashboard", to: "dashboard#show", as: :dashboard
33
+ get "dashboard/*path", to: "dashboard#proxy", as: :dashboard_proxy
34
+ end
data/docs/AGENTS.md ADDED
@@ -0,0 +1,220 @@
1
+ # AGENTS.md — Rails Agent onboarding
2
+
3
+ Guide for **external coding agents** (Cursor, Claude Code, Codex, etc.) and humans building on Rails Agent.
4
+
5
+ ## What this platform is
6
+
7
+ Rails Agent is a **fullstack agent platform for Rails**: you write agents as Ruby directories under `app/agents/`, connect provider credentials (BYOK) in the cloud dashboard, then **test, deploy, and monitor** at `/agents`.
8
+
9
+ Billing: **fixed company subscription** + **metered usage at provider/infrastructure cost** + **transparent 1% service fee**.
10
+
11
+ ## Agent taxonomy (pick one)
12
+
13
+ | Type | Main purpose | Example |
14
+ |------|--------------|---------|
15
+ | **Knowledge** | Understand and answer | Order support from Rails data and policy docs |
16
+ | **Workflow** | Execute predictable processes | Verify → approve → refund → notify |
17
+ | **Operations** | Coordinate unpredictable real-world work | Incident or customer escalation coordination |
18
+ | **Monitoring** | Observe changes and respond | Inventory, error, or SLA watcher |
19
+
20
+ Use the matching base class: `RailsAgents::KnowledgeAgent`,
21
+ `WorkflowAgent`, `OperationsAgent`, or `MonitoringAgent`.
22
+
23
+ Legacy aliases (deprecated): `ChatAgent` → Knowledge, `BackgroundAgent` → Operations.
24
+
25
+ ## Run response schema (integrate into product)
26
+
27
+ Every provider (OpenAI, Anthropic, Gateway, OSS) normalizes to one shape.
28
+ Your app should not branch on provider-specific payloads.
29
+
30
+ | Field | Use |
31
+ |-------|-----|
32
+ | `result.output_text` | Final Markdown answer for chat / email / Slack |
33
+ | `result.output` | Legacy alias for `output_text` |
34
+ | `result.output_data` | Optional structured Hash for Rails branching (`nil` if text-only) |
35
+ | `result.items` | Typed turn: `message` (+ `result` when `output_data` present) |
36
+ | `result.format` | Always `"markdown"` for message content |
37
+ | `result.trace` | Tools / debug — Monitor, not the product answer |
38
+
39
+ ```ruby
40
+ result = StoreAssistant.run("Where is ORD-1001?", session_id: "user-1")
41
+ puts result.output_text
42
+ payload = result.output_data # Hash or nil
43
+ ```
44
+
45
+ Consumption by taxonomy:
46
+
47
+ - **Knowledge** — render Markdown (`output_text`); tables for catalogs
48
+ - **Workflow** — show `output_text`; branch on `output_data` (status, ids)
49
+ - **Operations** — post `output_text`; handoff via `output_data`
50
+ - **Monitoring** — alert with `output_text`; automate from `output_data`
51
+
52
+ Public docs: https://rails-agent.com/docs/run-response
53
+
54
+ ## Progressive path
55
+
56
+ ### 1. Connect workspace
57
+
58
+ ```bash
59
+ bundle add rails-agent-stack
60
+ bin/rails generate rails_agents:install
61
+ bin/dev # open http://localhost:3000/agents
62
+ ```
63
+
64
+ Sign up / connect at `/agents`. Platform API key is written to `config/rails_agents_credentials.yml` — **not** your OpenAI/Anthropic keys.
65
+
66
+ ### 2. First agent: database Knowledge (fastest win)
67
+
68
+ ```bash
69
+ bin/rails generate rails_agents:agent store_assistant --type knowledge --database
70
+ bin/rails db:seed # if demo data exists
71
+ ```
72
+
73
+ Edit `app/agents/store_assistant/agent.rb` — tools call your ActiveRecord models. Attach BYOK in cloud dashboard → **Settings → Providers** (reference name e.g. `:company_openai`).
74
+
75
+ ```ruby
76
+ class StoreAssistant < RailsAgents::KnowledgeAgent
77
+ model :gpt_5_mini, provider: :openai, credential: :company_openai
78
+ memory :conversation, provider: :mem0, recall: 5
79
+
80
+ tool :lookup_order do |order_number:|
81
+ # wire to your models
82
+ end
83
+ end
84
+ ```
85
+
86
+ Test locally:
87
+
88
+ ```bash
89
+ bundle exec rails-agents run store_assistant "Where is order ORD-DEMO-1001?"
90
+ bundle exec rails-agents sync store_assistant
91
+ ```
92
+
93
+ Dashboard uses `GET /agents/schema` to discover tables for database setup — keep that endpoint available.
94
+
95
+ ### 3. Tools
96
+
97
+ Add Ruby tool blocks in `agent.rb` or files under `tools/`. Tools run in your Rails app context.
98
+ Start with one read-only tool and test it before adding side effects.
99
+
100
+ ### Workspace Library (share only when reuse is real)
101
+
102
+ Agent-specific capabilities stay under `app/agents/<slug>/`. Capabilities used
103
+ by multiple agents have one canonical source under:
104
+
105
+ ```text
106
+ app/agents_library/
107
+ ├── tools/
108
+ ├── skills/
109
+ ├── packages/
110
+ ├── knowledge/
111
+ └── connectors/
112
+ ```
113
+
114
+ Attach shared sources through `app/agents/<slug>/imports.yml`:
115
+
116
+ ```yaml
117
+ version: 1
118
+ imports:
119
+ - kind: skill
120
+ slug: triage
121
+ from: library/skills/triage.rb
122
+ - kind: knowledge
123
+ slug: shipping_policy
124
+ from: library/knowledge/shipping_policy.md
125
+ - kind: package
126
+ slug: frontend_design
127
+ from: library/packages/frontend_design
128
+ ```
129
+
130
+ `bundle exec rails-agents sync NAME` safely resolves these paths and includes
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
133
+ duplicating generated copies in Git.
134
+
135
+ Shared Ruby tool files are organization boundaries, not a new DSL. Register the
136
+ tool in `agent.rb` using the normal `tool` block and call the shared module or
137
+ service from that block.
138
+
139
+ ### 4. Connectors
140
+
141
+ Add external SaaS integrations via Connect in the cloud dashboard (OAuth-managed actions). Use a local Ruby tool for your own database; use a connector for systems such as Notion, Sheets, or HubSpot.
142
+
143
+ ### 5. Skills
144
+
145
+ Composable behaviors in `skills/` — reference with `skill :name, from: "skills/name.rb"`.
146
+
147
+ ### 5b. Packages (agentic package manager)
148
+
149
+ **Package** is the installable primitive. Search Skills.sh, Microsoft APM, and
150
+ Smithery from the dashboard (**Library → Packages** or agent **Build → Packages**),
151
+ or via CLI:
152
+
153
+ ```bash
154
+ bundle exec rails-agents packages "refund"
155
+ bundle exec rails-agents add-package skills_sh:owner/repo/skill \
156
+ --registry skills_sh --agent store_assistant --source owner/repo
157
+ ```
158
+
159
+ Rails Agent downloads the upstream package, converts it into:
160
+
161
+ ```text
162
+ app/agents/<slug>/packages/<name>/package.yml
163
+ app/agents/<slug>/packages/<name>/SKILL.md
164
+ app/agents/<slug>/skills/<name>.rb # capability ready immediately
165
+ ```
166
+
167
+ and can save it to the workspace Library like tools/skills/plugins.
168
+
169
+ | Primitive | Meaning |
170
+ |-----------|---------|
171
+ | **Tool** | One deterministic Ruby action |
172
+ | **Skill** | Multi-step playbook (how to do work) |
173
+ | **Package** | Installable capability from external registries |
174
+ | **Connector** | External SaaS (OAuth Connect) |
175
+ | **Knowledge** | Docs / DB sources for grounding |
176
+ | **Library** | Workspace reuse of any of the above |
177
+
178
+ ### 6. Playbooks
179
+
180
+ Clone a Playbook when you want a proven starting structure, then customize the generated files locally. Playbooks can combine instructions, tools, and skills.
181
+
182
+ ### 7. Channels
183
+
184
+ Scaffold stubs live in `channels/`. Install connectors from `/agents` dashboard (Slack, web chat, API, cron, etc.).
185
+
186
+ ### 8. Evals
187
+
188
+ Add cases under `evals/*.yml`. Run on deploy from dashboard or `bundle exec rails-agents evals NAME`.
189
+
190
+ ### 9. Deploy & monitor
191
+
192
+ ```bash
193
+ bundle exec rails-agents deploy store_assistant
194
+ bundle exec rails-agents logs store_assistant
195
+ bundle exec rails-agents traces store_assistant
196
+ ```
197
+
198
+ Use `/agents` for runs, cost, traces, and eval results.
199
+
200
+ ## Model DSL (BYOK)
201
+
202
+ ```ruby
203
+ # Explicit provider + cloud credential reference (no secrets in repo)
204
+ model :gpt_5_mini, provider: :openai, credential: :company_openai
205
+
206
+ # Legacy cloud-routed (still supported, not default in new scaffolds)
207
+ model :auto
208
+ ```
209
+
210
+ Credential symbols map to encrypted records in Rails Agent Cloud — never commit API keys.
211
+
212
+ ## Do not use (deprecated)
213
+
214
+ - **Chat authoring / cloud pull** — build locally; push with `rails-agents sync`. CLI `pull` remains for compatibility only.
215
+
216
+ ## References
217
+
218
+ - Gem README: [README.md](README.md)
219
+ - Product spec: [docs/PRD.md](docs/PRD.md)
220
+ - Website: https://rails-agent.com/docs/getting-started
data/docs/PRD.md ADDED
@@ -0,0 +1,89 @@
1
+ # Rails Agent — Product Requirements Document
2
+
3
+ > **`rails-agent-stack` gem** (OSS, mounts into Rails) + **Rails Agent Cloud** (managed backend). Build agents locally with docs and external coding agents; test, deploy, and monitor at `/agents`.
4
+
5
+ ## 1. Mission
6
+
7
+ Make Rails Agent the **fullstack agentic platform for Rails**: developers scaffold agents in `app/agents/`, attach **BYOK** model credentials in the cloud, and use `/agents` to test, deploy, and monitor — with clear docs (**AGENTS.md**) for humans and external coding agents.
8
+
9
+ ## 2. Core Philosophy
10
+
11
+ 1. **Documentation-first** — AGENTS.md progressive path; no chat-based authoring.
12
+ 2. **Build in the repo** — Ruby agent directories, generators, external coding agents.
13
+ 3. **BYOK models** — provider credentials stored encrypted in cloud; referenced from agent DSL.
14
+ 4. **Four taxonomy types** — Knowledge, Workflow, Operations, Monitoring.
15
+ 5. **Test → deploy → monitor in one place** — `/agents` dashboard embed.
16
+ 6. **Transparent company billing** — fixed subscription + pass-through usage + 1% service fee.
17
+
18
+ ## 3. Product Surface
19
+
20
+ ### 3.1 `rails-agent-stack` gem
21
+
22
+ - Install: `bundle add rails-agent-stack` + `rails generate rails_agents:install`.
23
+ - Mountable engine at `/agents`: signup, connect, dashboard embed, **schema bridge** for DB setup.
24
+ - Agent-as-directory under `app/agents/<name>/`.
25
+ - **Product-facing taxonomy classes**: `KnowledgeAgent`, `WorkflowAgent`, `OperationsAgent`, `MonitoringAgent`.
26
+ - **DSL**:
27
+
28
+ ```ruby
29
+ class StoreAssistant < RailsAgents::KnowledgeAgent
30
+ model :gpt_5_mini, provider: :openai, credential: :company_openai
31
+ memory :conversation
32
+ knowledge_from "knowledge/**/*"
33
+
34
+ tool :lookup_order do |order_number:|
35
+ Order.find_by(number: order_number).as_json
36
+ end
37
+
38
+ channel :web
39
+ end
40
+ ```
41
+
42
+ - **CLI**: install, new, run, sync, deploy, logs, traces, evals. `pull` deprecated.
43
+ - **Generator**: `--type`, `--database` for first database Knowledge agent.
44
+ - Runtime: thin client to cloud for inference, deploys, observability. Tools execute in Rails app context.
45
+
46
+ ### 3.2 Rails Agent Cloud
47
+
48
+ - Auth, workspaces (company-scoped), API keys.
49
+ - **Credential vault** for BYOK (OpenAI, Anthropic, etc.) — referenced by symbol from agents.
50
+ - Model gateway resolves agent model + credential ref.
51
+ - Deploys, channels, vector/RAG, evals, traces, billing.
52
+ - **Billing**: Stripe company subscription + metered usage at cost + 1% service fee.
53
+ - API: runs, deploys, knowledge sync, files sync, logs, traces, evals.
54
+
55
+ ### 3.3 Dashboard
56
+
57
+ - Workspace: agents list, config (model/credential, tools, skills, memory, knowledge, channels, evals, deploy).
58
+ - **No Kip / chat authoring** — configuration and monitoring UI only.
59
+ - Schema discovery via parent page `GET /agents/schema`.
60
+
61
+ ## 4. Pricing
62
+
63
+ - **Company subscription** — fixed monthly fee per workspace (production).
64
+ - **Metered usage** — provider tokens and infrastructure at **pass-through cost**.
65
+ - **Service fee** — **1%** on metered usage, shown transparently on invoices.
66
+ - Sandbox/dev tier for building (non-production traffic).
67
+
68
+ ## 5. Non-Goals
69
+
70
+ - Chat-based agent authoring (removed).
71
+ - Storing provider API keys in the Rails app repo.
72
+ - Self-hosting / on-prem (cloud runtime).
73
+ - Non-Rails frameworks.
74
+
75
+ ## 6. Milestones
76
+
77
+ 1. **M1 — Gem + docs**: install, AGENTS.md, taxonomy, BYOK DSL, `--database` generator.
78
+ 2. **M2 — Cloud BYOK + billing**: credential vault, company plans, usage metering + 1%.
79
+ 3. **M3 — Channels + deploy**: Slack, web, API, cron end-to-end.
80
+ 4. **M4 — GA**: evals, monitoring agents, plugins/skills/playbooks in dashboard.
81
+
82
+ ## 7. SEO / Brand
83
+
84
+ - Name: **Rails Agent** / `rails-agent-stack`.
85
+ - Tone: confident, plainspoken, Rails-native.
86
+
87
+ ---
88
+
89
+ **Instruction to implementers**: Gem and boilerplate follow this doc. Cloud dashboard must remove authoring chat and implement BYOK + company billing.
Binary file
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Support < RailsAgents::KnowledgeAgent
4
+ model :gpt_5_mini, provider: :openai, credential: :company_openai
5
+ memory :conversation
6
+ knowledge_from "knowledge/**/*"
7
+
8
+ tool :lookup_order do |order_id:|
9
+ { id: order_id, status: "shipped", note: "Example only � wire to your Order model." }
10
+ end
11
+
12
+ skill :triage, from: "skills/triage.rb"
13
+ channel :slack
14
+ end
File without changes