AGENTS.md
Project Identity
Project Name: ratatui_ruby
Description: A high-performance Ruby wrapper for the Ratatui TUI library.
Architecture:
-
Frontend (Ruby): Pure
Dataobjects (Ruby 3.2+) defining the View Tree. Immediate mode. -
Backend (Rust): A generic renderer using
ratatuiandmagnusthat traverses the RubyDatatree and renders to the terminal buffer.
Stability & Compatibility
-
Project Status: Pre-1.0.
-
User Base: 0 users (internal/experimental).
-
Breaking Changes: Backward compatibility is NOT a priority at this stage. Since there are no external users, you are encouraged to refactor APIs for better ergonomics and performance even if it breaks existing code.
-
Requirement: All breaking changes MUST be explicitly documented in the CHANGELOG.mdβs Unreleased section to ensure transparency as the project evolves toward 1.0.
1. File & Coding Standards
Licensing & Copyright (Strict)
Every file must begin with an SPDX-compliant header. Use the following format:
# frozen_string_literal: true # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com> # SPDX-License-Identifier: AGPL-3.0-or-later
-
Ruby/Rust/Config files: Use comments appropriate for the language (
#or//). -
Markdown: Use HTML comment style
<!-- -->. -
Exceptions:
REUSE.tomlmanages exceptions (e.g., binary files or.gitignore).
Ruby Standards
-
Version: Tested against the latest releases of Ruby 3.2, 3.3, 3.4, and 4.0, and must work on all of them. Local development happens on the latest stable release.
-
Linter & Testing (CRITICAL):
-
ALWAYS use
bin/agent_rakefor running tests, linting, or checking compilation. -
NEVER run
bundle exec rakedirectly. NEVER runbundle exec ruby -Ilib:test ...directly. -
VIOLATION OF THIS RULE IS A CRITICAL ERROR.
-
Why?
-
Noise Reduction: Standard
rakeoutput includes massive amounts of Rust compilation noise that floods your context window, truncating the actual error message.bin/agent_rakecaptures this silently. -
Atomic Dump: Agents work best with a single βAtomic Dumpβ of the failure.
bin/agent_rakeprovides this by swallowing successful output and only printing the failure log if something goes wrong. -
Merged Output: It correctly merges stdout (Minitest failures) and stderr (Rust warnings) so you see them in temporal order.
-
-
Usage:
-
Runs default task (compile + test + lint):
bin/agent_rake -
Runs specific task:
bin/agent_rake test:ruby(for example)
-
-
Interpretation: If the User says βrake test failsβ or βfix the buildβ or βbin/agent_rake failsβ, they IMPLICITLY mean βrun
bin/agent_rakeand fix the reported errorsβ. Do not ask for clarification; just usebin/agent_rake.
-
-
Style:
-
Use
Data.definefor all value objects (UI Nodes). (Preferclass Foo < Data.define()overFoo = Data.define() do). -
Prefer
frozen_string_literal: true. -
Use
Minitestfor testing. -
Define types in
.rbsfiles. Donβt useuntypedjust because itβs easy; be comprehensive and accurate. Do not includeinitializein.rbsfiles; useself.newfor constructors instead. -
Every line of Ruby must be covered by tests that would stand up to mutation testing. This includes all examples in the
examples/directory; they should have corresponding tests inexamples/to ensure they continue to work as intended and serve as reliable documentation. Tests must be meaningful and verify specific behavior or rendering output; simply verifying that code βdoesnβt crashβ is insufficient and unacceptable. For UI widgets, this means usingwith_test_terminalto verify every character of the terminal bufferβs content. -
Every public Ruby class/method must be documented for humans in RDoc (preferred)βnot YARDβor markdown files (fallback), and must have
*.rbstypes defined. -
Every significant architectural and design decision must be documented for contributors in markdown files. Mermaid is allowed.
-
Rust Standards
-
Crate Type:
cdylib. -
Linter:
clippyandrustfmt. -
Bindings: Use magnus.
-
Platform: Support macOS (Apple Silicon), Linux, and Windows.
-
Linker Flags: Must handle macOS
-undefined dynamic_lookup. -
Every line of Rust must be covered by tests that would stand up to mutation testing. This includes every widget implementation in
ext/ratatui_ruby/src/widgets/; each must have atestsmodule with unit tests verifying basic rendering. Tests must be meaningful; simply verifying that code βdoesnβt crashβ or βcompilesβ is insufficient.
2. Directory Structure Convention
The project follows a standard Gem layout with an ext/ directory for Rust code.
/ βββ .cargo/ # Cargo configuration (linker flags) βββ .github/ # CI/CD workflows βββ bin/ # Executables (console, setup) βββ doc/ # Documentation source (markdown for RDoc) β βββ contributors/ # Design docs, ecosystem notes β βββ index.md βββ ext/ β βββ ratatui_ruby/ # RUST SOURCE CODE GOES HERE β βββ src/ β β βββ lib.rs # Entry point β βββ Cargo.toml β βββ extconf.rb # Makefile generator βββ lib/ β βββ ratatui_ruby/ β β βββ schema/ # Ruby Data definitions β β βββ version.rb β βββ ratatui_ruby.rb # Main loader βββ test/ β βββ data/ # Data-driven test files β βββ ratatui_ruby/ # Unit tests βββ vendor/ # Vendorized style configs (goodcop) βββ AGENTS.md # Context for AI agents βββ Gemfile βββ Rakefile βββ REUSE.toml # Compliance definition βββ ratatui_ruby.gemspec
3. Configuration & Tooling
Development Environment
-
Setup:
bin/setupmust handle both Bundler and Cargo dependencies. -
Pre-commit: Use
bin/agent_raketo ensure commit-readiness. See Ruby Standards for detailed instructions.
Documentation
-
The
doc/folder contains source markdown files that are included in RDoc output. Follow the structure: index.md ->contributors/| quickstart.md. -
The
tmp/rdoc/folder is auto-generated bybundle exec rake rerdoc. Never edit files intmp/rdoc/directly. -
Documentation should separate βUser Guideβ (Ruby API for TUI developers) from βContributor Guideβ (Ruby/Rust/Magnus internals).
-
Style Guide: You MUST follow the Documentation Style Guide. This dictates the Alexandrian/Zinsser prose style and strict RDoc formatting required for all public API documentation.
-
Donβt write .md files for something RDoc (Ruby) or rustdoc (Rust) can generate.
4. The Ruby <-> Rust Bridge Contract
The Ruby Side (lib/)
-
Refer to docs/contributors/design/ruby_frontend.md for detailed design philosophy regarding the Data-Driven UI and Immediate Mode paradigm.
The Rust Side (ext/)
-
Refer to docs/contributors/design/rust_backend.md for detailed implementation guidelines, module structure, and rendering logic.
5. Deployment / Release
-
The gem builds a native extension.
-
Artifact naming: Ensure the output shared library matches Rubyβs expectation on macOS (rename
.dylibto.bundleif necessary during the build process inextconf.rborRakefile).
6. Commit Message
-
Commits:
-
Who commits: Only humans should affect the git index and history. Do not stage (do not
git add). Do not commit. Just suggest a commit message. -
When: At the end of each task, before reporting the task as complete to the user, suggest the commit message.
-
What: Consider not just what you remember, but also everything in the
git diffandgit diff --cached. -
Who commits: Only humans should affect the git index and history. Do not stage (do not
git add). Do not commit. Just suggest a commit message. -
When: At the end of each task, before reporting the task as complete to the user, suggest the commit message.
-
What: Consider not just what you remember, but also everything in the
git diffandgit diff --cached.
-
-
Format:
-
Format: Use Conventional Commits.
-
Structure:
type(scope): description(e.g.,feat(widget): add Gauge widget). -
Subject line: Concise summary (50 chars or less).
-
Structure:
type(scope): description(e.g.,feat(widget): add Gauge widget). -
Subject line: Concise summary (50 chars or less).
-
-
Body: Explanation if necessary (wrap at 72 chars).
-
Explain why this is the implementation, as opposed to other possible implementations.
-
Skip the body entirely if it's rote, a duplication of the diff, or otherwise unhelpful.
-
DO NOT list the files changed or the edits made in the body. Do not provide a bulleted list of changes. Use prose to explain the problem and the solution.
-
Do not use markdown syntax (no backticks, no bolding, no lists, no links), except as required in AI Attribution. The commit message must be plain text.
-
Explain why this is the implementation, as opposed to other possible implementations.
-
Skip the body entirely if it's rote, a duplication of the diff, or otherwise unhelpful.
-
DO NOT list the files changed or the edits made in the body. Do not provide a bulleted list of changes. Use prose to explain the problem and the solution.
-
Do not use markdown syntax (no backticks, no bolding, no lists, no links), except as required in AI Attribution. The commit message must be plain text.
-
-
Footer: AI attribution if generated by an agent, sourcehut ticket if implemented by a ticket, or both.
-
Format: Use Conventional Commits.
-
Structure:
type(scope): description(e.g.,feat(widget): add Gauge widget). -
Subject line: Concise summary (50 chars or less).
-
-
Body: Explanation if necessary (wrap at 72 chars).
-
Explain why this is the implementation, as opposed to other possible implementations.
-
Skip the body entirely if it's rote, a duplication of the diff, or otherwise unhelpful.
-
DO NOT list the files changed or the edits made in the body. Do not provide a bulleted list of changes. Use prose to explain the problem and the solution.
-
Do not use markdown syntax (no backticks, no bolding, no lists, no links), except as required in AI Attribution. The commit message must be plain text.
-
-
Footer: AI attribution if generated by an agent, sourcehut ticket if implemented by a ticket, or both.
-
-
AI Attribution:
-
Always include AI attribution in the footer if the commit was generated or significantly assisted by an AI agent. This is mandatory for transparency and compliance. This is NOT optional.
-
Amp: ββ Generated with Amp
-
Always include AI attribution in the footer if the commit was generated or significantly assisted by an AI agent. This is mandatory for transparency and compliance. This is NOT optional.
-
Amp: ββ Generated with Amp
Co-Authored-By: Amp noreply@ampcode.com ββ
-
Antigravity: Specify the model used in the footer. Examples: ββ Generated with Antigravity
Co-Authored-By: Gemini 3 Pro (High) noreply@google.com
Generated with AntigravityCo-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com ββ
-
Gemini 3: ββ Generated with Gemini 3 Pro
Co-Authored-By: Gemini 3 Pro noreply@google.com ββ
-
JetBrains Junie: ββ Generated with JetBrains Junie
Co-Authored-By: Junie junie@jetbrains.com ββ
-
-
Sourcehut Tickets:
-
If the commit implements a specific ticket, include a footer:
Implements: https://todo.sr.ht/~kerrick/ratatui_ruby/<id> -
Do NOT include this footer if you were not given a specific ticket ID or URL. Do not hallucinate or guess ticket URLs.
-
This must be the last item in the footer, if present.
-
7. Definition of Done
Before considering a task complete and returning control to the user, you MUST ensure:
-
Default Rake Task Passes: Run
bin/agent_raketo execute ALL tests and linting. Do not rely on partial test runs, orrake test, orrake lintalone. Confirm it passes with no new errors or warnings. -
Documentation Updated: If public APIs or observable behavior changed, update relevant
doc/files, README.md, and/orratatui_ruby-wikifiles,. -
Changelog Updated: If public APIs, observable behavior, or gemspec dependencies changed, update CHANGELOG.mdβs Unreleased section according to the Semantic Versioning and Keep a Changelog specifications.
-
What belongs in CHANGELOG: Only changes that affect application developers or library developers who use or depend on ratatui_ruby:
-
New public APIs or widget parameters
-
Observable behavior changes (rendering, styling, layout)
-
Deprecations and removals
-
Breaking changes
-
New public examples (if they demonstrate significant features)
-
Performance improvements that affect applications
-
What does NOT belong in CHANGELOG: Internal changes that donβt affect downstream users:
-
Test additions or improvements
-
Documentation updates, RDoc fixes, markdown clarifications
-
Refactors of internal code
-
New or modified example code (unless the example itself is a major feature)
-
Internal tooling, CI/CD, or build configuration changes
-
Code style, linting, or type signature changes
-
Changelogs should be useful to downstream developers (both app and library developers), not simple restatements of diffs or commit messages.
-
-
Commit Message Suggested: You MUST ensure the final message to the user includes a suggested commit message block. This is NOT optional.