Add AI skills for ramenctl commands - #455
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughAdds a skills subsystem and CLI integration: embedded templates for six skills and five agents, rendering and write-once installation logic, agent validation and --agent flag for ramenctl init, console helpers, config helper refactor, tests covering installs and errors, and expanded docs. ChangesAI Agent Skills Installation
Sequence Diagram(s)sequenceDiagram
participant ComponentA
participant ComponentB
ComponentA->>ComponentB: observable interaction
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
3e8d18a to
e709294
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/skills.md`:
- Around line 69-76: The "Available skills" table contains markdown links
pointing to generated files (e.g., [ramenctl-init](ramenctl-init/SKILL.md),
[ramenctl-validate-clusters](ramenctl-validate-clusters/SKILL.md),
[ramenctl-validate-application](ramenctl-validate-application/SKILL.md),
[ramenctl-gather-application](ramenctl-gather-application/SKILL.md),
[ramenctl-test-run](ramenctl-test-run/SKILL.md),
[ramenctl-test-clean](ramenctl-test-clean/SKILL.md)) which are not in the repo
and produce broken links; update the table to remove or replace these dead
targets by either converting the linked labels to plain text (e.g.,
ramenctl-init, ramenctl-validate-clusters, etc.) or pointing them to a stable
docs location that exists in the repo/site instead, ensuring each entry uses an
existing path or no link at all.
In `@pkg/skills/install.go`:
- Around line 46-57: The current logic in pkg/skills/install.go skips installing
a skill whenever skillDir exists (using os.Mkdir and isDir), which prevents
retry when the directory was created but SKILL.md was never written; change the
check so that you only skip when the SKILL.md file exists inside skillDir.
Concretely: after detecting an existing directory (skillDir), test for the
presence of filepath.Join(skillDir, "SKILL.md") and only append to skipped
(cmd.Slug+"-"+skill.Name) and continue if that SKILL.md exists; if SKILL.md is
missing, proceed with creation/writing of the SKILL.md file. Apply the same
SKILL.md existence check to the other similar block around the code handling
lines 65-68 so retries can repair incomplete installs.
- Around line 18-21: The exported Install path currently panics on unknown agent
names; change the behavior in the agents lookup (the block referencing
agents[agentName]) to return false (and optionally an error log) instead of
calling panic so the caller can handle failure; ensure the lookup in the Install
function (or the surrounding function that references agent, ok :=
agents[agentName]) uses the ValidateAgent contract and returns false when ok is
false rather than terminating the process.
In `@pkg/skills/skills_test.go`:
- Line 25: Update the section comment strings that currently read like "// ---
Install per agent ---" (and the other similar markers "// --- ... ---") so they
end with proper punctuation (e.g., change to "// --- Install per agent. ---");
locate each occurrence by searching for the exact comment text in
pkg/skills/skills_test.go (including the other instances mentioned) and add a
trailing period to conform to the Go comment punctuation guideline.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 80e66e35-8df7-4687-9891-93e66c34ce35
📒 Files selected for processing (25)
README.mdcmd/commands/init.godocs/gather.mddocs/init.mddocs/skills.mddocs/test.mddocs/test/plan.mddocs/validate.mdpkg/config/config.gopkg/console/console.gopkg/skills/agent.gopkg/skills/install.gopkg/skills/skills.gopkg/skills/skills_test.gopkg/skills/templates/agents/bob.tmplpkg/skills/templates/agents/claude.tmplpkg/skills/templates/agents/codex.tmplpkg/skills/templates/agents/cursor.tmplpkg/skills/templates/agents/generic.tmplpkg/skills/templates/skills/gather-application.tmplpkg/skills/templates/skills/init.tmplpkg/skills/templates/skills/test-clean.tmplpkg/skills/templates/skills/test-run.tmplpkg/skills/templates/skills/validate-application.tmplpkg/skills/templates/skills/validate-clusters.tmpl
✅ Files skipped from review due to trivial changes (10)
- pkg/skills/templates/skills/test-run.tmpl
- docs/gather.md
- pkg/skills/templates/agents/claude.tmpl
- docs/validate.md
- pkg/skills/templates/agents/generic.tmpl
- pkg/skills/templates/agents/codex.tmpl
- pkg/skills/templates/agents/bob.tmpl
- pkg/skills/templates/skills/init.tmpl
- pkg/skills/templates/skills/test-clean.tmpl
- docs/test.md
🚧 Files skipped from review as they are similar to previous changes (1)
- pkg/console/console.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/project.mdc)
Use proper punctuation in comments (end sentences with periods) in Go source files
Keep files focused - separate files for different concerns (e.g.,
html.go,yaml.go,summary.go)
Files:
pkg/skills/agent.gocmd/commands/init.gopkg/config/config.gopkg/skills/skills.gopkg/skills/install.gopkg/skills/skills_test.go
**/*.{go,yaml,yml,sh,makefile,Makefile}
📄 CodeRabbit inference engine (.cursor/rules/project.mdc)
All files need SPDX license headers - check existing files for the format
Files:
pkg/skills/agent.gocmd/commands/init.gopkg/config/config.gopkg/skills/skills.gopkg/skills/install.gopkg/skills/skills_test.go
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/project.mdc)
Use
helpers.FakeTime(t)for time-dependent tests to ensure reproducibility in Go tests
Files:
pkg/skills/skills_test.go
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Discuss the design with the user before making code changes
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Show example changes to make sure we are in the right direction before making code changes
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Ask for more details if the user request is not clear
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: List possible alternatives to make the change
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Do the minimal change needed, no extra code that is not needed right now
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Avoid unrelated changes such as spelling, whitespace, etc.
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Keep changes small to make human review easy and avoid mistakes
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Run `make pre-commit` to format code and check lint and spelling errors before committing
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Use package tests for quick iteration with `go test ./pkg/foo/...`
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Before committing, run `make test` to catch issues early
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Check existing code for error formatting conventions when implementing error handling
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: NEVER commit directly to main branch
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: NEVER push to GitHub without user review
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Keep commits small and focused
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: For unrelated changes, create a new branch from main
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Avoid complicated git operations. The user can rebase later
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Commit messages should explain why the change was made - what are we trying to do
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Commit messages should explain how the change affects the user - what is the new or modified behavior
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: If the change affects performance, include measurements and description of how we measured in commit messages
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: If the change modifies the output, include example output with and without the change in commit messages
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: If the change introduces new logs, show example logs including the changed or new logs in commit messages
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: If several alternatives were considered, explain why we chose the particular solution in commit messages
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Discuss the negative effects of the change if any in commit messages
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: If the change includes new APIs, describe the new APIs and how they are used in commit messages
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Avoid describing details that are best seen in the diff in commit messages
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: Include `Assisted-by: Cursor/{model}` footer with full model version (e.g., `Cursor/Claude Opus 4.6`) in commit messages
Learnt from: CR
Repo: RamenDR/ramenctl
Timestamp: 2026-05-17T22:06:03.056Z
Learning: NEVER add `Co-authored-by` trailer in commit messages - use only `Assisted-by`
📚 Learning: 2026-05-17T21:55:49.135Z
Learnt from: nirs
Repo: RamenDR/ramenctl PR: 455
File: docs/init.md:123-126
Timestamp: 2026-05-17T21:55:49.135Z
Learning: This repository does not use markdownlint for enforcement. During code reviews, do not flag or comment on markdownlint rule warnings (e.g., MD028, MD014, MD040 or any other markdownlint rule IDs) in markdown files, even if they appear in diff output or editor warnings.
Applied to files:
README.mddocs/init.mddocs/skills.mddocs/test/plan.md
📚 Learning: 2026-05-17T21:55:51.068Z
Learnt from: nirs
Repo: RamenDR/ramenctl PR: 455
File: docs/test/plan.md:209-209
Timestamp: 2026-05-17T21:55:51.068Z
Learning: Do not report or flag violations that would be raised by the markdownlint rules (the “MD*” family, e.g., MD040 for fenced-code-language). Since this repository does not use markdownlint, markdown formatting checks tied to markdownlint should be ignored across all Markdown files.
Applied to files:
README.mddocs/init.mddocs/skills.mddocs/test/plan.md
🪛 markdownlint-cli2 (0.22.1)
README.md
[warning] 87-87: Dollar signs used before commands without showing output
(MD014, commands-show-output)
docs/init.md
[warning] 126-126: Blank line inside blockquote
(MD028, no-blanks-blockquote)
docs/skills.md
[warning] 84-84: Dollar signs used before commands without showing output
(MD014, commands-show-output)
docs/test/plan.md
[warning] 209-209: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 272-272: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 301-301: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 328-328: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 355-355: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 381-381: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 403-403: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 432-432: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (18)
pkg/skills/skills_test.go (1)
27-83: LGTM!Also applies to: 87-97, 101-161, 165-207, 211-236, 240-317
README.md (1)
80-90: LGTM!Also applies to: 103-103
docs/init.md (1)
6-7: LGTM!Also applies to: 11-11, 17-17, 23-23, 26-30, 33-42, 50-64, 73-83, 97-106, 123-126
docs/skills.md (1)
1-65: LGTM!Also applies to: 78-117
docs/test/plan.md (1)
24-30: LGTM!Also applies to: 199-199, 209-219, 224-228, 242-242, 256-259, 260-390, 401-447
pkg/config/config.go (3)
35-49: LGTM!
51-78: LGTM!
80-81: LGTM!cmd/commands/init.go (4)
6-21: LGTM!
23-35: LGTM!
37-41: LGTM!
43-59: LGTM!pkg/skills/templates/agents/cursor.tmpl (1)
1-17: LGTM!pkg/skills/templates/skills/gather-application.tmpl (1)
1-112: LGTM!pkg/skills/templates/skills/validate-application.tmpl (1)
1-164: LGTM!pkg/skills/templates/skills/validate-clusters.tmpl (1)
1-122: LGTM!pkg/skills/agent.go (1)
1-78: LGTM!pkg/skills/skills.go (1)
1-110: LGTM!
| if err := os.MkdirAll(agent.SkillsDir, 0o755); err != nil { | ||
| console.Error("failed to create directory %q: %s", agent.SkillsDir, err) | ||
| return false | ||
| } |
There was a problem hiding this comment.
Can be removed, creating a skill directory can use os.MkdirAll.
| console.Error("expected directory but found file %q", skillDir) | ||
| return false | ||
| } | ||
| } |
There was a problem hiding this comment.
This can be simplified to os.MkdirAll() call - it already handles existing directory, and any other error is fatal.
|
|
||
| func isRegularFile(path string) bool { | ||
| info, err := os.Stat(path) | ||
| return err == nil && info.Mode().IsRegular() |
There was a problem hiding this comment.
This hides errors in os.Stat(). Should return (bool, error) so the caller can report fatal errors.
|
|
||
| dir := filepath.Dir(agent.ContextFile) | ||
| if dir != "." { | ||
| if err := os.MkdirAll(dir, 0o755); err != nil { |
There was a problem hiding this comment.
should not create world readable directory.
| } | ||
|
|
||
| func installSkills(cmd Command, agent agent) bool { | ||
| if err := os.MkdirAll(agent.SkillsDir, 0o755); err != nil { |
There was a problem hiding this comment.
should not create world readable directory.
| for _, skill := range skills { | ||
| skillDir := filepath.Join(agent.SkillsDir, cmd.Slug+"-"+skill.Name) | ||
|
|
||
| if err := os.Mkdir(skillDir, 0o755); err != nil { |
There was a problem hiding this comment.
should not create world readable directory.
| func isDir(path string) bool { | ||
| info, err := os.Stat(path) | ||
| return err == nil && info.IsDir() | ||
| } |
There was a problem hiding this comment.
same as isRegularFile - hides error, but we should be able to remove it.
| deploy, protect, failover, relocate, unprotect, undeploy. | ||
|
|
||
| **This typically takes 15-20 minutes per test case.** Multiple test cases | ||
| run in parallel. |
There was a problem hiding this comment.
Need to tell the agent to NEVER run this in the background. When testing bob, it started the tests in the background, and this makes it very hard to monitor progress and ruin the user experience.
There was a problem hiding this comment.
There is not way to prevent running in background in bob without failing. Current instructions works well for Cursor and fail with bob when running the test command. I'll file a bob bug report.
|
Thanks for the pointer — I checked #455 and ran the focused package test locally: $ go test ./pkg/skills
ok github.com/ramendr/ramenctl/pkg/skills 0.014sThe implementation is cleaner than I expected: each agent has its own context template, and Codex/generic sharing One edge case I’d consider before merging: ramenctl init -a generic # creates AGENTS.md pointing at .agents/skills/...
ramenctl init -a bob # creates .bob/skills/... but AGENTS.md already exists, so it is not updatedThe command succeeds and prints Bob’s advanced-mode hint, but the existing Possible small fix without abandoning write-once ownership:
This is exactly the kind of “files installed, semantics not wired” fidelity issue that tends to be hard to debug later. The current tests are good on fresh installs; this would cover the mixed-agent/idempotent path. |
Thanks for looking at this, this is unlikely usage for ramenctl but possible. I think the right way would be to add an agent specific section in AGENETNS.md like: ## ramenctl skills for bob
Content for bob...
## ramenctl skills
Content for generic agent ...The command can parse the markdown and make sure it has the right section, or warn if the section does not exist. In the worst case AGENTS.md will have content for both bob and generic agent, so we waste some tokens, but the agent should be able to find the skills. Or maybe we have a way to add bob instructions in .bob/ like cursor/claude? |
| t.Errorf("%s should not contain template syntax", path) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Missing tests - install twice with different agents
- Install generic after bob was installed
- instructions for generic agent should be added to AGENTS.md
- validate skills for both agents
- Install bob after generic was installed
- instructions for bob should be added to AGENTS.md
- validate skills for both agents
- Install codex after bob
- instructions for codex should be added to AGENTS.md
- validate skills for both agents
- Install bob after codex
- instructions for bob should be added to AGENTS.md
- validate skills for both agents
- Install same agent twice
- agent specific section appears once
|
That sectioned I’d make the sections deliberately machine-detectable, not just human-readable, because this is where idempotency tends to get slippery. Something like: <!-- ramenctl:skills agent=bob dir=.bob/skills command=ramenctl -->
## ramenctl skills for Bob
...
<!-- /ramenctl:skills -->
<!-- ramenctl:skills agent=generic dir=.agents/skills command=ramenctl -->
## ramenctl skills for generic agents
...
<!-- /ramenctl:skills -->Then the installer can keep the write-once/low-risk model but still answer a precise question: “does the existing context file wire the skills dir I just installed?” Minimal behavior I’d aim for in this PR:
If Bob has/gets a native context path under |
Bob supports .bob/rules/*.md - we should use it instead of AGENTS.md. This leaves only Codex and Generic sharing AGENTS.md. Since both use .agents/skills, we can have the same content in the context file. The skill index is not needed by codex, but some wasted context for codex is better than having to maintain per agent markdown sections for one agent. With this we can actually remove codex from the list since we don't have specific codex configuration, the generic configuration works. |
|
That makes the shape much cleaner. If Bob has native In that version I agree with removing The acceptance criterion I’d keep is still the same, just simpler:
That avoids the token-waste issue in |
|
Quick follow-up with a concrete artifact from this thread: I shipped the Bob/native-rules mapping in The relevant behavior is intentionally small: npx --yes pluribus-context@latest init --tools bob
npx --yes pluribus-context@latest sync
npx --yes pluribus-context@latest audit --json --fidelity-reportThe Bob target now writes {
"toolId": "bob",
"nativeDiscoverySurface": ".bob/rules/*.md",
"genericFallback": false,
"manualActivationRequired": false
}So the external sanity check I’d apply here is: if No need to adopt Pluribus, but the native-vs-fallback vocabulary is now executable if it helps test/review this PR. |
caioribeiroclw-pixel
left a comment
There was a problem hiding this comment.
Re-checked the refreshed branch at f35cad61 against the native-discovery concern from the May thread. The Bob path is now wired to .bob/rules/ramenctl.md while skills stay under .bob/skills, and the focused test asserts that native context file:
$ go test ./pkg/skills
ok github.com/ramendr/ramenctl/pkg/skills 0.015sI also verified Bob no longer routes through AGENTS.md. That resolves the mixed-agent/write-once mismatch I raised: Bob, Cursor, and Claude now use their own discovery surfaces; Codex/generic remain the shared AGENTS.md fallback. The current mapping looks consistent to me.
|
@caioribeiroclw-pixel Thanks for reviewing! But this is a draft and not ready for review. I rebased for a demo, but this needs more works. |
|
You're right — sorry, I jumped the review boundary. I treated the force-push plus green focused tests as review-ready even though the PR is still marked draft. The native-path check was useful to me, but the formal approval was premature. I won't add further review feedback until you mark it ready or explicitly ask. Thanks for correcting me. |
|
@caioribeiroclw-pixel Your review it is very helpful. I just don't want to waste your time on reviewing partial work. |
We use only the Assisted-by trailer to credit AI assistance. The Co-authored-by trailer is added automatically by Cursor and should not be included. Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Add the init skill that guides AI agents through configuring
config.yaml for disaster recovery clusters. The skill covers:
- Discovering kubeconfigs and configuring clusters
- Looking up OCM cluster names and finding the clusterSet
- Discovering DRPolicies and matching peer classes for pvcSpecs
- Configuring test options (drPolicy, pvcSpecs, tests)
Skills use Go templates with {{.CommandName}} and {{.CommandSlug}}
to support both "ramenctl" and "odf dr" command names. YAML
frontmatter is always included for tool auto-discovery.
Assisted-by: Cursor/Claude Opus 4.6
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Guide AI agents through running validate clusters, checking the result, opening the HTML report, inspecting gathered data, and troubleshooting problems. Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Guide AI agents through looking up protected applications, running validate application, opening the HTML report, inspecting gathered data, troubleshooting problems, and suggesting validate clusters for a complete picture. Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Guide AI agents through looking up protected applications, running gather application, and inspecting the gathered data structure. The gathered data can be archived and uploaded for bug reports. Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Guide AI agents through running DR flow tests and cleaning up afterwards. The agent will not clean up without an explicit user request to preserve evidence from failed tests. Both skills require passing validate clusters before proceeding. Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Add per-agent context file templates that introduce ramenctl to AI agents. Every agent gets a short overview explaining that ramenctl manages disaster recovery and listing the available commands (init, validate, gather, test). Each template targets the agent's native context file format: - cursor.tmpl → .cursor/rules/ramenctl.mdc with alwaysApply frontmatter so the overview is always in context when working in the project. - claude.tmpl → CLAUDE.md, plain markdown overview. - codex.tmpl → AGENTS.md, plain markdown overview. - bob.tmpl → AGENTS.md with an instruction to switch to advanced mode, which is required for Bob to discover skills. - generic.tmpl → AGENTS.md with a full skill index listing each SKILL.md path, since a generic agent may not auto-discover skills. Cursor, Claude Code, and Codex auto-discover skills in their native directories, so their context files only need the project overview. Bob and generic agents need extra help: Bob needs to be told to enable advanced mode, and generic agents need explicit paths to each skill. Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Add Warn for non-fatal warnings at step level, and StepHint for suggestions indented under step messages (Pass/Warn). Hint remains for top-level suggestions (e.g. after Info in browser.go). The⚠️ emoji is two Unicode code points: ⚠ (U+26A0) + variation selector (U+FE0F). The variation selector forces color emoji rendering but consumes one visual cell in some terminals (e.g. macOS Terminal.app), eating the trailing space. We compensate with an extra space after⚠️ to align with single code point emojis like ✅. Ideally the console would be stateful, tracking the current nesting level so a single Hint function could indent correctly. For now we use two functions with hardcoded indentation. Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Install(commandName, agent) installs skill files and a context file for the specified AI agent. Each agent gets skills in its expected directory and a context file that instructs the agent to read the matching skill before responding to user requests. Installation uses a write-once model - existing skill files and context files are never overwritten, preserving user modifications. A second run skips existing files with a warning. Public API: - Install(commandName, agent) - install skills and context file for the specified agent. Returns true on success. - ValidateAgent(agent) - return error if the agent name is not supported. Used for early flag validation. - Agents() - return sorted list of supported agent names. Used to generate the --agent flag help text. Supported agents: bob, claude, codex, cursor, generic (default). The package is split into three files: - agent.go: agent definitions, validation, and agent list - skills.go: skill/command types and template rendering - install.go: installation orchestration and file I/O Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Extend `ramenctl init` to install AI agent skills after creating the
configuration file. The --agent (-a) flag selects the target agent,
with the agent list generated from skills.Agents().
The init command now runs two steps with the same pattern:
- config.Install() - create config file (warn if exists)
- skills.Install() - install skills and context file
Add config.Install() to handle console output and write-once
behavior, matching the skills.Install() pattern. The previous
CreateSampleConfig() is now private since callers should use
Install() instead.
The --agent flag is validated early in PreRunE so cobra shows
usage on invalid input.
Example run:
% ramenctl init -h
Create configuration file and install AI skills
Usage:
ramenctl init [flags]
Flags:
-a, --agent string AI agent to install skills for (bob, claude, codex, cursor, generic) (default "generic")
--envfile string ramen testing environment file
-h, --help help for init
Global Flags:
-c, --config string configuration file (default "config.yaml")
--interactive enable interactive features (default auto)
% ramenctl init -a bob
⭐ Using config "config.yaml"
🔎 Initializing ...
✅ Created config file "config.yaml" - please modify for your clusters
✅ Created skills for Bob in ".bob/skills/"
✅ Created context file "AGENTS.md"
Use "/mode advanced" in Bob to enable skills
✅ Init completed
Assisted-by: Cursor/Claude Opus 4.6
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Add docs/skills.md describing agentic usage, available skills, where skills are installed per agent, and how to add a new agent. Update docs/init.md with current help output, example output, and a brief AI skills section linking to docs/skills.md for details. Add tips about agentic usage to docs/validate.md, docs/gather.md, and docs/test.md. Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
New test cases: - Init with each agent (cursor, claude, codex, bob) - Init with invalid --agent - Re-init is safe (write-once model) Updated test cases: - Create default config: includes skills and context file output - Create named config: includes skills installation - Create config from envfile: includes skills installation - Config already exists: skills and context file still installed Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Highlight that ramenctl is agentic-ready out of the box and link to the new AI skills guide. Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Based on feedback from bob, the instructions should be more explicit. Reword to work better with bob. Signed-off-by: Nir Soffer <nsoffer@redhat.com>
NOTE: need to rebase and fix the right commit. Signed-off-by: Nir Soffer <nsoffer@redhat.com>
792ee1b to
93f8d73
Compare
Without this, the agent picks an output directory on its own (e.g. odf/namespace-application) and the user has no way to change it. Add a "Pick an output directory" step to the validate-application, gather-application, test-run, and test-clean skills. The validate-clusters skill already had this step but used a vague <env> placeholder. All skills now suggest a unique name with a timestamp including hours and minutes (e.g., out/clusters-2026-07-20-19-46). This ensures consistent naming across runs and avoids reusing an existing directory, which causes output files with numeric suffixes (-2, -3) that confuse the agent when inspecting results. Also rename <output-dir> to <output-directory> to match the step heading and reinforce that the agent should use the directory chosen in the previous step. Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
When a ramenctl command times out (e.g. slow S3 endpoint), the agent retries it in the background with a new output directory. This wastes time and creates unexpected partial output. Add rules to all agents context to not run commands in the background and not retry on timeout — report it and let the user decide. Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
When an S3 endpoint is slow, ramenctl hangs because it has no timeout
on S3 calls. The agent shell harness kills the command after 120
seconds, then the agent retries in the background with a new output
directory — wasting time and creating unexpected partial output.
Remove time estimates from the skills ("takes a few seconds locally
and about a minute on remote clusters") since the agent uses them to
guess a timeout. Add explicit rules to all agent context files:
- Run ramenctl commands without a timeout (timeout=0 for bob)
- Do not run commands in the background
- Do not retry on timeout — report it and let the user decide
The real fix is adding S3 call timeouts in ramenctl itself so it
fails fast instead of hanging. These skill changes are a workaround
until that is done.
Assisted-by: Cursor/Claude Opus 4.6
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
The agent invents a config schema when extracting the hub kubeconfig:
kubectl get drpc -A --kubeconfig \
$(yq '.clusters[] | select(.role == "hub") | .kubeconfig' config.yaml)
The config does not have a role field — clusters are named keys. Tell
the agent to read the hub kubeconfig path from clusters.hub.kubeconfig
in the config file instead of guessing the schema.
Assisted-by: Cursor/Claude Opus 4.6
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
The previous generic "do not retry" rules were not strong enough — bob kept using 120-180s timeouts and retrying commands in the background. Use bob's own suggested format with CRITICAL/ALWAYS/NEVER emphasis and exact execute_command XML examples showing timeout=0 and background=false. Also add "NEVER cancel or kill a running command." Whether this helps depends on the harness — if it enforces a 180s timeout regardless of what the agent requests, these rules cannot override it. The real fix is separating running commands from watching progress (RamenDR#459) so the agent can safely timeout on progress and restart without losing work. Assisted-by: Cursor/Claude Opus 4.6 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Why skills?
ramenctl makes disaster recovery manageable, but adopting it still
requires learning commands, flags, and output conventions. AI coding
assistants can handle this for the user — configuring clusters,
running validations, interpreting reports — but only if they know
how ramenctl works.
Skills are structured markdown files that teach an AI agent how to
drive ramenctl. Each skill covers one subcommand: when to use it,
prerequisites, step-by-step workflow, and how to interpret results.
This makes it easy to get started with ramenctl and reduces the
learning curve for new users.
What this looks like in practice
Installing skills with
ramenctl initSkills are embedded in the ramenctl binary as Go templates and
installed by
ramenctl init. The--agent(-a) flag selects theformat for your AI agent:
Supported agents:
-a bob.bob/skills/.bob/rules/ramenctl.md-a claude.claude/skills/CLAUDE.md-a cursor.cursor/skills/.cursor/rules/ramenctl.mdc.agents/skills/AGENTS.mdInstallation uses a write-once model — existing skill files and context
files are never overwritten, preserving user modifications. Running
initagain skips existing files with a warning.Implementation
pkg/skills/templates/skills/as Gotext/templatefiles. They support dynamic command names(
ramenctlvsodf dr).pkg/skills/templates/agents/,one per agent, providing project overview and skill discovery
instructions tailored to each agent's format.
pkg/skillspackage is split into three focused files:agent.go: agent definitions, validation, andAgents()listskills.go: skill/command types and template renderinginstall.go: installation orchestration and file I/OInstall(commandName, agent),ValidateAgent(agent),Agents(). Adding a new agent is one constant + one map entry +one template file.
ramenctl initvalidates the--agentflag early viaPreRunE, then runs two steps with the same pattern:config.Install()andskills.Install().console.Warn()andconsole.StepHint()added for non-fatalwarnings and indented hints.
Tested with
Issues
Fixes #453