Skip to content

feat: holodeck skill command (catalog + claude/cursor/codex/gemini installers)#812

Merged
ArangoGutierrez merged 27 commits into
NVIDIA:mainfrom
ArangoGutierrez:feat/holodeck-skill-cmd
May 21, 2026
Merged

feat: holodeck skill command (catalog + claude/cursor/codex/gemini installers)#812
ArangoGutierrez merged 27 commits into
NVIDIA:mainfrom
ArangoGutierrez:feat/holodeck-skill-cmd

Conversation

@ArangoGutierrez
Copy link
Copy Markdown
Collaborator

Problem

Users adopting holodeck via an AI coding agent (Claude Code, Cursor,
Codex, Gemini CLI) have no first-class way to teach the agent the
CLI. Today the only path is "paste --help into the agent."

Approach

Adds a holodeck skill command with two subcommands:

  • holodeck skill list — show the embedded catalog (table/json/yaml).
  • holodeck skill add <name> --claude|--cursor|--codex|--gemini
    install the skill in the agent's native format. --global writes
    to user config; --all installs every skill in the catalog;
    --all-agents is a shortcut for all four agent flags.

Skills are authored once as Claude Code SKILL.md files under
pkg/skill/data/skills/<name>/, embedded into the binary via
//go:embed. A Renderer interface translates per agent. Codex
and Gemini share a single-file install path (AGENTS.md /
GEMINI.md); the install is idempotent via section markers.

v1 ships one skill: using-holodeck.

Testing

  • Table-driven unit tests for parser and all four renderers.
  • Integration tests for the installer with t.TempDir():
    per-file atomic write, single-file section splice (append /
    replace / preserve other sections), overwrite-prompt /
    --force interaction.
  • CLI subcommand action tests for flag validation.
  • Manual end-to-end smoke per-agent in /tmp documented in the plan.

Spec / plan

  • Spec: docs/superpowers/specs/2026-05-14-holodeck-skill-cmd-design.md
  • Plan: docs/superpowers/plans/2026-05-14-holodeck-skill-cmd.md

Breaking changes

None. New command, no existing surface modified.

ArangoGutierrez added a commit to ArangoGutierrez/holodeck that referenced this pull request May 15, 2026
urfave/cli/v2's default parser stops parsing flags after the first
non-flag arg, so 'holodeck skill add using-holodeck --claude' was
rejected with 'must specify at least one of --claude/...'. Rewrites
the in-binary --help examples and README to put agent flags before
the positional skill name, matching actual parser behavior.

Caught during Team Lead review of draft PR NVIDIA#812.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Copy link
Copy Markdown
Collaborator Author

@ArangoGutierrez ArangoGutierrez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Principal Engineer review — PR #812

(Posted by Team Lead on behalf of principal-engineer subagent. See ~/.claude/CLAUDE.md PE-review protocol.)

Verdict

APPROVE

Architecture

  • Renderer interface (pkg/skill/render.go:27-43) is cleanly factored: four methods, single responsibility, no leaky abstractions. The SingleFile() discriminator is the right shape for the two install models.
  • Install() (pkg/skill/install.go:54-113) cleanly switches on r.SingleFile() and dispatches to installSingleFile vs the per-file atomic flow. Both paths share writeFileAtomic.
  • cmd/cli/skill/ correctly mirrors cmd/cli/<cmd>/ pattern. Dependency direction is right: cmd/cli/skillpkg/skill, no upward leaks.
  • pkg/skill has zero non-stdlib deps beyond yaml.v2 (parser) and go-isatty (already in tree). No transitive churn.
  • Mild scope concern: command struct (cmd/cli/skill/skill.go:30-52) is shared between list and add; outputFormat only meaningful for list, other 10 fields only for add. Follows existing patterns; acceptable.

Go conventions

  • Errors wrapped at every call site (install.go:126,134,138,149,155,172, etc.) with %w. errors.Is(err, os.ErrNotExist) used correctly.
  • Receivers correct (value receivers on stateless renderers; consistent).
  • context.Context deliberately absent — appropriate for short synchronous CLI ops on local FS.
  • "Accept interfaces, return structs" shape held: Renderer consumed where defined; *xRenderer returned from NewXRenderer.
  • No init(), no globals, no any.

Security

  • gosec G304 (os.ReadFile(dest) at install.go:165): False positive. dest is computed from r.InstallPath(...), which is bounded to known string constants (.codex/AGENTS.md, .gemini/GEMINI.md, ~/.codex/..., ~/.gemini/...).
  • gosec G301 (MkdirAll(..., 0o755) at install.go:133): Acceptable. These are config dirs (.claude/skills/, .cursor/rules/, etc.) — user-readable is conventional and matches how Claude Code / Cursor / Codex / Gemini already create them. 0o750 would satisfy gosec; not worth a behavior change. Consider // #nosec G301 -- config dir convention annotation for clean lint output.
  • Path-traversal — defense-in-depth gap (non-blocking): parseSkill (skill.go:43-75) does not validate the name field. s.Name flows unsanitized into filepath.Join(".claude", "skills", s.Name, "SKILL.md") and filepath.Join(".cursor", "rules", s.Name+".mdc"). Safe today because the catalog is //go:embed-only (compile-time, trusted). The moment a future PR adds --file <local-SKILL.md> or a remote catalog, a name: ../../etc/cron.d/evil becomes a traversal write. Recommend a ^[a-z0-9][a-z0-9-]{0,63}$ allowlist regex in parseSkill. Cheap, future-proofs the package.
  • writeFileAtomic (install.go:132-159) — correct temp + rename with cleanup-on-err.
  • installSingleFile has a benign concurrency race (read → splice → write, no flock). Two concurrent holodeck skill add against the same AGENTS.md would lose one update. Out of v1 scope; flag for follow-up.

Test quality

Spot-checked every test file. No theater tests detected.

  • TestParseSkill (skill_test.go): table-driven, six cases (valid + 5 error paths). Literal expected strings derived independently of impl. Fails if parseSkill body deleted.
  • TestClaudeRendererRender (render_claude_test.go:36): asserts against fully-derived literal "---\nname: demo\ndescription: A demo skill\n---\n\n# Body\n\nDo the thing.\n".
  • TestSpliceSection_* (install_test.go:27-72): three cases (append, replace, only-touch-named-skill) with literal substrings, count checks (bytes.Count(... == 1), surrounding-content preservation. Catches splice regressions.
  • TestInstall_SingleFile_* / TestInstall_PerFile_*: invoke production functions on t.TempDir() and read back. Real I/O.
  • TestRunAdd_*: validation tests assert specific error substrings; TestRunAdd_DryRun_ClaudeOnly and TestRunAdd_AllAgents_SetsAllFour go through the full Catalog+Install pipeline.
  • TestBuildAddCommand_DescriptionUsesFlagFirstExamples (add_test.go:161-174) is a particularly nice doc-regression guard for the urfave/cli/v2 quirk fixed in ad00a640.
  • Tests are deterministic: no time.Now, no rand, no map-iteration ordering reliance. Catalog is sorted before assertions touch it.
  • Minor caveat: TestRunAdd_DryRun_ClaudeOnly and TestRunAdd_AllAgents_SetsAllFour use os.Chdir(t.TempDir()) and are not t.Parallel()-safe. Currently fine; flag if anyone adds t.Parallel() later.

YAGNI / scope

Implementation honored the deferral. No Remove(), no tag filter, no TUI picker, no remote catalog plumbing. Renderer interface is exactly what the four shipped agents need.

SKILL.md content

  • Frontmatter description (SKILL.md:3) is well-shaped for Claude Code's skill-triggering matcher: starts with "Use when...", names concrete user intents, names the trigger noun ("holodeck CLI"), lists scope. Matcher-friendly.
  • Aspirational content (list, status, ssh, scp, cleanup, os list) is per Team Lead direction; flagged for separate reconciliation.

Blocking issues

none

Non-blocking suggestions

  • Add a name regex validator in parseSkill for defense-in-depth.
  • Suppress G301 with // #nosec G301 -- config dir convention or downgrade to 0o750.
  • Add a brief comment on installSingleFile documenting the concurrent-write race.

Follow-up issues to file

  1. Parser fix (ad00a640 follow-up): urfave/cli/v2 → v3 migration or interspersion shim. The in-binary --help showing holodeck skill add --claude using-holodeck will confuse users who reach for the natural holodeck skill add using-holodeck --claude and silently get the "must specify at least one of --claude/..." error.
  2. SKILL.md aspirational content reconciliation: trim to commands that exist on main (create, delete, dryrun) OR ship the referenced subcommands before v0.3.0 cut. v0.3.0 is in bug-fix sprint per .claude/CLAUDE.md, so cutting the aspirational sections is the lower-risk path.
  3. Skill-name validation regex: low-priority hardening before opening the catalog source to anything non-embed.

@ArangoGutierrez ArangoGutierrez marked this pull request as ready for review May 15, 2026 14:52
ArangoGutierrez added a commit to ArangoGutierrez/holodeck that referenced this pull request May 16, 2026
urfave/cli/v2's default parser stops parsing flags after the first
non-flag arg, so 'holodeck skill add using-holodeck --claude' was
rejected with 'must specify at least one of --claude/...'. Rewrites
the in-binary --help examples and README to put agent flags before
the positional skill name, matching actual parser behavior.

Caught during Team Lead review of draft PR NVIDIA#812.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
@ArangoGutierrez ArangoGutierrez force-pushed the feat/holodeck-skill-cmd branch from ad00a64 to c48bc50 Compare May 16, 2026 06:34
@coveralls
Copy link
Copy Markdown

coveralls commented May 16, 2026

Coverage Report for CI Build 26209564134

Coverage increased (+0.9%) to 48.745%

Details

  • Coverage increased (+0.9%) from the base build.
  • Patch coverage: 150 uncovered changes across 9 files (342 of 492 lines covered, 69.51%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
pkg/skill/install.go 151 58 38.41%
cmd/cli/skill/add.go 122 103 84.43%
cmd/cli/skill/list.go 50 37 74.0%
pkg/skill/embed.go 25 17 68.0%
pkg/skill/render_cursor.go 20 15 75.0%
pkg/skill/render_claude.go 21 17 80.95%
pkg/skill/render_codex.go 19 16 84.21%
pkg/skill/render_gemini.go 15 12 80.0%
pkg/skill/skill.go 35 33 94.29%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 11558
Covered Lines: 5634
Line Coverage: 48.75%
Coverage Strength: 0.54 hits per line

💛 - Coveralls

Pure-function parser that splits a SKILL.md file into Skill{Name,
Description, Body}. Rejects missing name/description, empty body,
and missing frontmatter delimiters. Foundation for the catalog.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
//go:embed pulls every pkg/skill/data/skills/<name>/SKILL.md into the
binary at compile time. Catalog() walks the embedded FS, parses each
file, and returns a sorted []Skill. Includes a placeholder
using-holodeck skill so the embed has content; final content lands
in a later commit.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Renderer is the per-agent translation point. The Claude renderer
emits Skill content verbatim as <install-dir>/.claude/skills/<name>/
SKILL.md. Project-local default; --global resolves to $HOME.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Translates SKILL.md frontmatter (name, description) into Cursor's
.mdc frontmatter (description, globs, alwaysApply). Project-local
default; --global resolves to $HOME.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Renders skill content as a section block delimited by
<\!-- BEGIN/END holodeck-skill:<name> --> markers. The installer
will use these markers in a later commit to make append/replace
idempotent in the shared AGENTS.md file.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Mirrors the Codex section-block output. Installs to GEMINI.md
(project-local) or ~/.gemini/GEMINI.md (global).

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Install() ties Renderer to the filesystem. Per-file agents get an
atomic write with overwrite prompt (TTY) / error (non-TTY) unless
--force is set; --dry-run skips the write entirely. Single-file
agents get spliceSection: append when absent, replace when present,
malformed-existing falls through to append (never destructive).
Parent directories are created with 0755.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Scaffolds cmd/cli/skill following the cmd/cli/os subcommand pattern.
'skill list' reads the embedded catalog and emits table/json/yaml
output via pkg/output, matching 'holodeck list -o ...'.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Resolves the (skills x renderers) matrix from flags and calls
pkgskill.Install for each pair. Validation: requires an agent flag,
requires a skill name (or --all), rejects --stdout with multi-target,
rejects --all combined with a positional name. Errors include the
available-skill list for discoverability.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Registers the new skill command alongside the existing create/delete/
dryrun subcommands. 'holodeck skill list' and 'holodeck skill add'
now reachable from the CLI binary.

Adds TestNewCommand_MainGoWiringContract to assert the full surface
main.go consumes: non-nil, Name == "skill", non-empty Usage, both
'list' and 'add' subcommands present.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Replaces the placeholder body with a real guide covering env.yaml
shape, create/list/status/ssh/scp/delete/cleanup workflows, output
flags, and common pitfalls (credentials, region, OS, cache, VPC
leak). Source of truth lives next to the code so it versions with
CLI changes.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
README gets a quickstart for 'holodeck skill list' and 'holodeck
skill add'. CLI top-level --help already lists the new command via
urfave/cli's default COMMANDS rendering; no template edits needed
because main.go does not define a CustomAppHelpTemplate on this
branch.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
pkg/skill imports gopkg.in/yaml.v2 directly to parse SKILL.md
frontmatter. 'go mod tidy' reflects this by moving the entry from
the indirect-require block to the direct one. No new modules
vendored; go.sum and vendor/modules.txt are unchanged.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
urfave/cli/v2's default parser stops parsing flags after the first
non-flag arg, so 'holodeck skill add using-holodeck --claude' was
rejected with 'must specify at least one of --claude/...'. Rewrites
the in-binary --help examples and README to put agent flags before
the positional skill name, matching actual parser behavior.

Caught during Team Lead review of draft PR NVIDIA#812.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
- Check fmt.Fprintf/Fprintln return values in add.go, list.go, install.go
- Tighten MkdirAll permission to 0o750 in install.go (gosec G301)
- Annotate os.ReadFile calls where the destination path is bounded
  by Renderer.InstallPath or t.TempDir() (gosec G304 false positive)
- Tighten test WriteFile permission to 0o600 (gosec G306)
- Use fmt.Appendf instead of []byte(fmt.Sprintf(...)) (gocritic fmtappendf)
- Move Renderer interface satisfaction check to a package-level var
  declaration so the explicit interface type is preserved without
  triggering staticcheck ST1023

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
The shipped skill referenced rhel-9 (no such OS), a flat
kubernetesVersion field (actual schema nests under kubernetes.version
with installer: kubeadm), and spec.instance.amiID (actual path is
spec.instance.image.imageId). Rewrites the env.yaml example against
examples/v1alpha1_environment.yaml and verifies every command and
flag against the binary's --help output.

Also adds workflows for the get and update subcommands, an
'OS image discovery' section covering os list/describe/ami, and
corrects the dry-run anti-pattern to reference the dryrun subcommand
(create has no --dry-run flag).

Closes NVIDIA#814.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
parseSkill now rejects skill names that don't match
^[a-z0-9][a-z0-9-]{0,63}$. The catalog is //go:embed today so this
is defense-in-depth, but it hardens the parser against future
loaders that read SKILL.md from disk or network. Without this,
a SKILL.md with 'name: ../../etc/cron.d/evil' would let renderers
write outside the intended directory via filepath.Join.

Adds table-driven cases for path-traversal, leading-hyphen,
uppercase, underscore, and embedded-space rejections.

Closes NVIDIA#815.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
The earlier docs commit showed 'holodeck os ami <id> <region>' with
region as a positional. The actual command takes --region as a
required flag (and --arch as optional). Update the OS image
discovery section to match the binary's actual flag set.

Caught by re-verifying every command in SKILL.md against the
binary's --help output.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Two QA findings caught by the parallel review pass:

1. The env.yaml example nested 'os: ubuntu-22.04' under 'instance.image'.
   The Image struct in api/holodeck/v1alpha1/types.go has no OS field;
   the OS field lives directly on Instance. Non-strict YAML unmarshal
   silently dropped the misplaced key, so users following the example
   would have been given the default Ubuntu 22.04 AMI regardless of
   what they set. Move 'os' to be a direct child of 'instance' (sibling
   of 'type' and 'region') and add a commented-out alternative showing
   how to set an explicit imageId.

2. The output-flags section grouped 'os list' with the read commands
   that accept '-o table|json|yaml'. The 'os list' command in
   cmd/cli/os/os.go has no Flags slice — its output is a hardcoded
   tabwriter. Note this explicitly instead of implying flag parity.

Also align the OS pitfall to reference 'spec.instance.os' rather than
the wrong 'spec.instance.image.os'.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Address QA mutation-spot-check gap: the regex caps skill names at 64
characters but no test exercised that bound. Add a 65-char case
('a' repeated) that must be rejected. Mutating '{0,63}' to '{0,}'
would now fail this test.

Also rename the prior 'empty after trim' case to 'embedded space',
matching what it actually exercises (parseSkill does not trim;
the regex rejects the space char).

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Three more bugs surfaced by a third-pass QA audit against actual
source code:

1. 'dryrun (no AWS calls)' was wrong. pkg/provider/aws/dryrun.go:25-70
   makes read-only AWS describe-* API calls (checkInstanceTypes,
   checkImages, getInstanceTypeArch) and requires valid credentials.
   Reword to 'read-only; no resources created' and note credential
   dependency.

2. 'holodeck update <id>' was documented as 'idempotent re-run'. With
   no flags it is a no-op: cmd/cli/update/update.go:212 sets
   needsProvision := m.reprovision and line 350-352 prints 'No changes
   to apply'. Replace with concrete flag-driven examples
   (--reprovision, --add-driver, --add-kubernetes, --add-toolkit,
   --label) sourced from update.go --help.

3. 'auth.keyName / auth.privateKey are environment-variable names, not
   literals' was the opposite of true. pkg/provider/aws/create.go:493
   and cluster.go:699 pass Spec.KeyName literally to EC2 RunInstances;
   PrivateKey is used literally as a filesystem path. The canonical
   example file uses HOLODECK_AWS_ACCESS_KEY_ID-shaped placeholders,
   but holodeck never calls os.Getenv on them — they are templates
   users must replace. Replace the env.yaml example with realistic
   placeholders ('my-aws-keypair', '~/.ssh/my-aws-key.pem'), rewrite
   the credentials pitfall to make the literal vs env-var split
   explicit, and fix the anti-pattern accordingly.

Also clarify that 'get kubeconfig -o' is an output PATH (not a format
selector) so it isn't confused with 'list -o table|json|yaml'.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
…egex

The new 65-char rejection case (added in c61cff3) catches a
{0,63}->{0,} loosening. The matching tightening mutation
({0,63}->{0,62}) would silently break legitimate 64-char names with
no test failure. Add a 64-char valid case to lock down the upper
bound.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
… description

The parent `skill` command's Description has the same urfave/cli/v2
flag-parsing pitfall that add_test.go already guards against on the
`add` subcommand: any example shown as `skill add <name> --flag` is
unrunnable because urfave/cli/v2 stops parsing flags after the first
positional, and the action then fails with 'must specify at least one
of --claude/--cursor/--codex/--gemini/--all-agents'.

Mirror the regression guard so the Description shown by
`holodeck skill --help` cannot drift back to the broken ordering. The
regex rejects `skill add <kebab-name> --(claude|cursor|codex|gemini|
all-agents)` and a sanity assertion requires the canonical
flag-first form `--claude using-holodeck` to be present, so removing
all examples doesn't accidentally pass the guard.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
urfave/cli/v2's default parser stops consuming flags after the first
positional, so the previous examples shown by `holodeck skill --help`
were unrunnable as printed:

  $ holodeck skill add using-holodeck --claude
  Error: must specify at least one of --claude/--cursor/--codex/--gemini/--all-agents

The flag is silently dropped because `using-holodeck` is treated as
the first positional, after which `--claude` is rejected as another
positional rather than parsed.

Rewrite both copy-pastable examples in the Description so the agent
flag precedes the skill-name positional, matching the pattern used by
the `add` subcommand's own help and the canonical install commands
in the embedded SKILL.md docs:

  holodeck skill add --claude using-holodeck
  holodeck skill add --claude --cursor using-holodeck

The regression guard added in the prior commit now passes.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
…KILL.md

When an AI agent reads using-holodeck/SKILL.md it copy-pastes the
commands verbatim, so any example in the broken `<id> --flag` form
makes the agent's first attempt fail in a way that's hard to diagnose
without reading urfave/cli/v2 source.

Three classes of fix in this file:

- Rewrite the `update` and `get kubeconfig` examples so flags come
  before the positional instance id (e.g. `update --instance-type … <id>`,
  `get kubeconfig -o ./kubeconfig <id>`). The `<id>` positional has to
  be last for the same urfave/cli/v2 reason.

- Make `cleanup` examples explicit that `--region us-west-2` (or
  `AWS_REGION=us-west-2` env) is required — `cleanup` does not infer
  the region from the saved instance metadata.

- Two new "Common pitfalls" entries:
    * Instance IDs are short hex strings (`a1b2c3d4`), not
      EC2-style `i-…` ARNs. Agents routinely confuse the two.
    * Flag-first ordering — `urfave/cli/v2` stops parsing flags after
      the first positional, with a pointer to which commands this
      bites (update, get kubeconfig, cleanup, skill add).

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
The original comment claimed the skill name came from the parent directory
name, but parseSkill ignores that string for the canonical Name (which is
read from the YAML frontmatter and validated against skillNameRE). The
directory name is only used as an error-message prefix. Reword the comment
so a future maintainer doesn't add redundant directory-name validation
based on the misleading wording.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
sigs.k8s.io/yaml is already a direct dependency of this module and is
the yaml library used in pkg/jyaml, pkg/utils/kubeconfig, and elsewhere.
Routing frontmatter parsing through it avoids introducing a second YAML
library and removes ~10k lines of vendored gopkg.in/yaml.v2 code.

sigs.k8s.io/yaml converts YAML to JSON internally and then uses
encoding/json, so the frontmatter struct tags switch from yaml: to json:
to match the rest of the repo (e.g. SkillListItem in cmd/cli/skill/list.go
already uses both).

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
@ArangoGutierrez ArangoGutierrez force-pushed the feat/holodeck-skill-cmd branch from 20766f2 to 5aebea7 Compare May 21, 2026 06:30
@ArangoGutierrez ArangoGutierrez merged commit 50d7138 into NVIDIA:main May 21, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants