Ruby in the Age of AI

enogrob.github.io · 2026-10-01 · by Long Nguyen ·generic
Software/Telecommunications Engineer

Ruby in the Age of AI

Edit this page Ruby in the Age of AI — Ruby DSLs and metaprogramming bridging Rails and AI-native software

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

1. Ruby already did this once 2. AI currently exposes too much infrastructure 3. From infrastructure to language 4. Why Ruby DSLs are different 5. Metaprogramming turns vocabulary into behavior 6. What an AI-native Ruby DSL could look like 7. The SDLC as a program 8. Agents as first-class language concepts 9. From DSL to a real system 10. A tiny executable prototype 11. Try it in 60 seconds 12. Ruby as a semantic layer 13. One declaration, many projections 14. 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 — Ruby DSL compressing AI infrastructure into higher-level intent

From Infrastructure to Language — a Ruby DSL turns AI building blocks into domain vocabulary.

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.

    Metaprogramming as a Multiplier — a small Ruby declaration expanding into runtime, knowledge, policies, tracing, orchestration, documentation, and graph behavior

    Metaprogramming as a Multiplier — a small declaration expands into executable system 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 SDLC as a Program — Discovery through Feedback expressed and orchestrated in Ruby

    The SDLC as a Program — describing, generating, and orchestrating the lifecycle in Ruby.

    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.

    From DSL to Real System — agents, knowledge, tools, policies, diagrams, documentation and runtime generated from Ruby

    From DSL to Real System — one expressive language can project into agents, knowledge, tools, policies, documentation, diagrams, and runtime.

    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
enogrob.github.io · 10 images · 16 links

Comments (0)

No comments yet