From Rails world to the age of AI. Rubyβs next opportunity may not be to become the language AI models are implemented in. It may be to become one of the best languages for creating the languages through which humans and AI describe, generate, and orchestrate software.
Ruby has been here before.
When Rails appeared, Ruby did not suddenly become closer to HTTP internals, SQL, sockets, or browser rendering. Something more interesting happened: Ruby made it possible to create a language closer to the Web domain.
resources :orders
class Customer < ApplicationRecord
has_many :orders
end
has_many :orders is technically a Ruby method call. But that is not how a Rails developer experiences it. It reads like a statement about the domain.
Rails took infrastructure and transformed it into vocabulary.
That abilityβsupported by blocks, symbols, closures, introspection, open classes, and metaprogrammingβbecame one of Rubyβs defining strengths.
And the age of AI may be creating another moment where that matters.
Contents
- Ruby already did this once
- AI currently exposes too much infrastructure
- From infrastructure to language
- Why Ruby DSLs are different
- Metaprogramming turns vocabulary into behavior
- What an AI-native Ruby DSL could look like
- The SDLC as a program
- Agents as first-class language concepts
- From DSL to a real system
- A tiny executable prototype
- Try it in 60 seconds
- Ruby as a semantic layer
- One declaration, many projections
- What comes next
Ruby already did this once
The current Rails Guides still describe Active Record associations as macro-style calls: concise declarations such as has_many :comments that generate or modify behavior at runtime.
class Author < ApplicationRecord
has_many :books
end
Conceptually, Rails changes the level at which the developer works:
DOMAIN INTENT
Author has many Books
β
RUBY / RAILS DSL
has_many :books
β
FRAMEWORK
associations Β· queries Β· methods Β· persistence behavior
The DSL does not merely save keystrokes. It changes what the program says.
That leads to the question behind this post:
If Rails made Ruby feel native to the Web, could DSLs make Ruby feel native to AI?
Rails world β AI-native Ruby
AI currently exposes too much infrastructure
Building AI-native software today quickly introduces a growing vocabulary:
Prompts Β· Context Β· Tools Β· MCP Β· RAG Β· Memory
Agents Β· Skills Β· Instructions Β· Guardrails
Handoffs Β· Workflows Β· Tracing Β· Evaluation
These are valuable primitives, but applications often have to assemble them explicitly. We are still close to the infrastructure layer.
Rails faced a related problem in another domain. Its answer was not to remove HTTP or SQL. It created a language closer to what developers were trying to express.
From infrastructure to language
Imagine expressing the domain directly:
agent :support_expert do
goal "Resolve customer issues"
knows :product,
:support_history
uses :github,
:ticketing,
:knowledge_base
remembers :conversation
follows :support_policy
hands_off_to :human_support,
when: :confidence_is_low
end
The interesting part is not that the syntax is pleasant. The interesting part is what those words can mean.
knows :product could expand into retrieval, access policy, context assembly, observability, and provenance. uses :github could expand into tool registration, permission checks, schemas, and runtime bindings. hands_off_to could become orchestration behavior.
The language expresses semantic intention. The framework decides how that intention becomes machinery.
Why Ruby DSLs are different
We could represent an agent with YAML:
agent:
name: discovery
knowledge:
- product
tools:
- github
output:
- discovery_report
That is structured and useful. Ruby can go further:
agent :discovery do
knows :product
uses :github
produces :discovery_report
when confidence < 0.70 do
request_more_evidence
end
end
The same artifact can be configuration, model, policy, specification, executable program, and extension point.
That matters because the AI domain is not stable. Its vocabulary is still evolving. Ruby lets the language evolve with the domain.
Metaprogramming turns vocabulary into behavior
Consider again:
has_many :orders
Rails can make this tiny declaration create methods, queries, relationships, and conventions around an association.
An AI-native DSL could do the same with a declaration such as:
agent :architect do
knows :architecture
produces :adr
end
A framework could expand it into:
- an agent definition;
- input and output contracts;
- knowledge bindings;
- retrieval configuration;
- tool permissions;
- prompts and context;
- observability and tracing;
- documentation;
- a node in an orchestration graph.
That is the deeper role of metaprogramming here:
Turning domain vocabulary into executable behavior.
The direction matters:
intent β vocabulary β Ruby DSL β metaprogramming β infrastructure
not the other way around.
What an AI-native Ruby DSL could look like
A first vocabulary might be surprisingly small:
AI.define do
agent :discovery do
goal "Understand the problem before proposing solutions"
observes :customer_interviews,
:support_tickets,
:roadmap
knows :product,
:architecture
distinguishes :evidence,
:inference,
:unknowns
uses :github,
:rag
produces :discovery_report
hands_off_to :planning
end
end
Notice what is missing: embedding dimensions, vector-database details, HTTP schemas, token budgets, and low-level runtime configuration.
Those concerns do not disappear. They move below the semantic layer, just as SQL does not disappear when Rails says has_many :orders.
The SDLC as a program
This becomes more interesting when applied to the whole software lifecycle.
The previous AI Across the SDLC work already gives us the domain vocabulary. We can now make that lifecycle explicit:
sdlc "CaseFlow" do
discovery do
sources :customer_interviews,
:support_tickets,
:roadmap,
:architecture_docs
distinguish :evidence,
:inference,
:unknowns
produce :discovery_report
end
planning do
consume :discovery_report
produce :prioritized_backlog,
:acceptance_criteria
end
architecture do
consume :discovery_report
produce :adr,
:component_map,
:api_contract
end
development do
implement :approved_architecture
end
testing do
verify :business_rules,
:integrations,
:critical_flows
end
review do
verify :quality,
:security,
:compliance
end
release do
require_all :passing_tests,
:approved_review
deploy :production
end
production do
observe :metrics,
:logs,
:traces,
:events
end
feedback do
learn_from :customers,
:usage,
:incidents
feed_into :discovery
end
end
Now the lifecycle is no longer only documentation. It is a model the machine can inspect, validate, transform, visualize, and potentially execute.
The DSL can express more than a sequence. It can encode conditions, concurrency, gates, and organizational policy.
after :development do
parallel do
run :testing
run :security_review
run :documentation
end
converge_at :release_readiness
end
policy :production_change do
require :tests
require :security_review
require_human_approval
end
Agents as first-class language concepts
An agent can become a native concept rather than a pile of configuration:
agent :discovery do
phase :discovery
knows :product, :customer_context
skills :product_discovery
uses :github
produces :discovery_report
hands_off_to :planning
end
GitHub Copilot already supports custom agents as Markdown-based agent profiles that can specify prompts, tools, and MCP servers. Agent Skills package instructions, scripts, and other resources in reusable skill directories that Copilot can load for specialized tasks.
That makes Copilot a useful target platform, but the Ruby DSL should sit above any one provider.
A declaration such as:
agent :discovery do
skills :product_discovery
tools :github
knowledge :product_docs
produces :discovery_report
end
could be compiled into platform-specific artifacts:
.github/
βββ agents/
β βββ discovery.agent.md
βββ skills/
β βββ product-discovery/
β βββ SKILL.md
βββ instructions/
βββ discovery.instructions.md
And agents can form a graph:
A useful language vocabulary starts to emerge:
π€ Agent who acts
β‘ Skill what it can do
π§ Tool what it can use
π Knowledge what it can know
π§ Memory what it can retain
π‘οΈ Policy what it may do
π¦ Artifact what it produces
π Event what triggers it
π Flow how work moves
From DSL to a real system
The DSL becomes interesting when a declaration creates multiple projections of the same intent.
agent :operations do
observes :metrics,
:logs,
:traces
knows :runbooks
uses :observability_platform
on :incident do
investigate
correlate_signals
suggest_remediation
end
end
The same semantic model could produce agent definitions, skills, tool schemas, policies, knowledge configuration, diagrams, Markdown documentation, JSON representations, and runtime configuration.
Ruby is no longer merely the runtime language. It becomes a semantic authoring layer.
One declaration, many projections
The clearest way to feel the potential is to look at one declaration and several outputs.
agent :discovery do
goal "Understand the problem"
knows :product
uses :github
produces :discovery_report
policy do
distinguish :evidence, :inference, :unknowns
end
end
From that single semantic source, a framework can project into multiple artifacts:
β JSON model
β Mermaid diagram
β Markdown documentation
β Agent profile
β Skill package
β Runtime configuration
That is where the Ruby DSL stops being merely expressive and starts becoming architecturally useful.
A tiny executable prototype
This post includes a small, dependency-free Ruby experiment. It deliberately avoids pretending to be a production framework. Its purpose is to test the central hypothesis: can a Ruby DSL become a semantic model that generates multiple useful artifacts?
The core declaration looks like this:
world = RubyAIDSL.define do
agent :discovery do
goal "Understand the problem before proposing solutions"
observes :customer_interviews, :support_tickets, :roadmap
knows :product, :architecture
distinguishes :evidence, :inference, :unknowns
skills :product_discovery
uses :github, :rag
produces :discovery_report
hands_off_to :planning
end
end
The same library can model a complete lifecycle:
world = RubyAIDSL.define do
sdlc :caseflow do
discovery { produce :discovery_report }
planning { consume :discovery_report; produce :prioritized_backlog }
architecture { produce :adr, :component_map }
development { implement :approved_architecture }
testing { verify :critical_flows }
review { verify :quality, :security }
release { require_all :passing_tests; deploy :production }
production { observe :metrics, :logs, :traces }
feedback { learn_from :production; feed_into :discovery }
end
end
Run it with ordinary Ruby:
ruby examples/agents.rb
ruby examples/sdlc.rb
ruby examples/generate.rb
The generator creates JSON, Markdown, and Mermaid projections from the same model.
Download the Ruby AI DSL support package
The prototype is intentionally small because the important thing at this stage is not the API surface. It is the direction:
human / AI intent
β
Ruby DSL
β
semantic model / AST
β
ββββββββββββββββ¬βββββββββββββββ¬βββββββββββββββ
GitHub Copilot β Agent runtimeβ Documentationβ
Mermaid β JSON β Other targetsβ
ββββββββββββββββ΄βββββββββββββββ΄βββββββββββββββ
Try it in 60 seconds
The quickest way to evaluate the idea is to run the support project and inspect what one Ruby definition can generate.
unzip ruby-ai-dsl-support.zip
cd ruby-ai-dsl-support
ruby examples/generate.rb
The generator writes multiple projections from the same semantic model:
generated/
βββ caseflow.json
βββ caseflow.md
βββ caseflow.mmd
The exact syntax is still experimental. The important part is that the same Ruby declaration becomes machine-readable data, human-readable documentation, and a visual model.
Ruby as a semantic layer
Large models do not need Ruby in order to reason. That is not the claim.
The opportunity is that natural language is expressive but ambiguous, while machine configuration is precise but often semantically poor. Ruby DSLs occupy an interesting middle ground:
Natural language Ruby DSL Machine config
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
expressive expressive precise
ambiguous structured rigid
not inherently executable executable
executable
human-first human + AI machine-first
An AI can generate the DSL. A human can read and review it. Ruby can execute it. A compiler can transform it. Another agent can reason about its structure.
That combination is valuable in an AI-native development environment.
What comes next
Python dominates much of todayβs AI implementation ecosystem. That does not mean every layer of an AI-native application must use the same language.
Ruby has a different strength: it is unusually good at creating languages inside the language.
Rails demonstrated it for Web development. RSpec did it for testing. Rake did it for tasks. Bundler did it for dependency declaration.
An AI-native generation of Ruby libraries could do the same for:
Agents Β· Knowledge Β· Tools Β· Skills Β· Policies
Workflows Β· Evaluation Β· Governance Β· Software delivery
So perhaps the interesting question is not:
Will AI bring Ruby back?
It is:
What kinds of languages become valuable when AI writes more of the implementation?
This post is not a proposal for a finished framework. It is an experiment around a more useful question:
Can Ruby become a semantic language for AI-native software?
The next practical step is to push the prototype beyond JSON, Markdown, and Mermaid and generate real AI assetsβagent profiles, skills, tool bindings, policies, and runtime configurationβfrom the same source language.
A natural follow-up is:
Building the First AI-Native DSL in Ruby
Abstraction tends to move upward:
Assembly
β
Programming languages
β
Frameworks
β
DSLs
β
AI
β
Human intent
If AI increasingly handles implementation, the valuable artifact may become the thing that expresses the intent, constraints, semantics, and structure of the system.
Ruby can help make that artifact executable.
Conclusion
Rails showed that programming becomes dramatically more powerful when the language moves closer to the problem domain.
AI may now be creating another such domain.
Agents, skills, tools, context, knowledge, policies, memory, evaluation, and orchestration are becoming important primitives of software engineering.
Ruby already possesses one of the most powerful mechanisms for turning domain concepts into executable language: its tradition of DSLs, backed by metaprogramming.
If Rails made Ruby feel native to the Web, perhaps DSLs can make Ruby feel native to AI.
And perhaps the next important Ruby framework will not primarily help us write more implementation.
It may help humans and AI express what software should become.
intent do
humans :define_meaning
ai :reason_and_create
ruby :make_it_a_language
end
References
- Ruby on Rails Guides β Active Record Associations
- GitHub Docs β About custom agents
- GitHub Docs β Adding agent skills for GitHub Copilot
- Previous post β AI Across the SDLC with GitHub Copilot
- Previous post β AI Across the SDLC β Part 01: Discovery & Product Planning