Skip to content

feat(codex): support workflow skills#1534

Open
borshyo wants to merge 2 commits intocoleam00:devfrom
borshyo:codex/codex-skills-support
Open

feat(codex): support workflow skills#1534
borshyo wants to merge 2 commits intocoleam00:devfrom
borshyo:codex/codex-skills-support

Conversation

@borshyo
Copy link
Copy Markdown

@borshyo borshyo commented May 2, 2026

Summary

Describe this PR in 2-5 bullets:

  • Problem: Codex workflow nodes could not explicitly preload Archon skills, even though local Codex sessions already have a skill model and workflows can declare skills:.
  • Why it matters: workflows that rely on provider-specific domain instructions need deterministic validation and runtime behavior; missing or silently ignored skills make agent runs hard to reproduce.
  • What changed: added provider-level skill resolution/loading for Codex, exposed assistants.codex.skillRoots, enabled Codex skills capability, wired workflow validation/CLI validation to provider-specific roots, and updated docs/tests.
  • What did not change (scope boundary): no MCP behavior is changed; this PR intentionally excludes the separate MCP workflow fixes and only touches skills/config/validation/docs/tests.

UX Journey

Before

User                   Archon workflow             Codex provider
────                   ───────────────             ──────────────
runs workflow ───────▶ node has skills: [...]
                       validates generic refs
                       sends prompt ─────────────▶ no workflow skill context loaded
reply ◀─────────────── Codex responds without selected SKILL.md instructions

After

User                   Archon workflow             Codex provider
────                   ───────────────             ──────────────
runs workflow ───────▶ node has skills: [...]
                       validates provider-specific refs
                       sends node config ────────▶ resolves SKILL.md
                                                  loads selected skill content
                                                  prepends skill context
reply ◀─────────────── Codex responds with selected skill instructions active

Architecture Diagram

Before

workflow YAML
  └─ skills: [...]
       └─ validator.ts ──> generic filesystem check

CodexProvider
  └─ sendQuery(prompt) ──> Codex SDK

config-loader.ts
  └─ assistants.codex (model/search/additionalDirectories only)

After

workflow YAML
  └─ skills: [...]
       ├─ validator.ts [~]
       │    ═══> resolveProviderSkillReferences() [+]
       └─ CodexProvider.sendQuery() [~]
            ═══> resolveSkillReferences() [+]
            ═══> loadResolvedSkills() [+]
            ═══> prepend skill context before Codex SDK turn

config-loader.ts [~]
  └─ assistants.codex.skillRoots [+]

@archon/providers/skills [+]
  ├─ default roots: repo/home .agents/.codex/.claude skills
  ├─ explicit path refs for Codex
  └─ fail-fast unreadable higher-precedence candidates

Connection inventory (list every module-to-module edge, mark changes):

From To Status Notes
workflow skills: schema workflow validator modified trims/validates non-empty skill refs
workflow validator @archon/providers/skills new validates refs with provider-specific roots
Codex provider @archon/providers/skills new resolves and loads selected SKILL.md files at runtime
core config loader Codex assistant defaults modified carries skillRoots into provider defaults
CLI validate command workflow validator modified passes default provider and Codex skill roots into workflow validation
docs workflow authoring / skills guides modified documents Codex/Pi/Claude support and Codex roots

Label Snapshot

  • Risk: risk: medium
  • Size: size: M
  • Scope: workflows|providers|cli|config|docs|tests|skills
  • Module: providers:codex, providers:skills, workflows:validator, cli:validate

Change Metadata

  • Change type: feature
  • Primary scope: workflows|providers

Linked Issue

  • Closes #
  • Related #
  • Depends on # none
  • Supersedes # none

Validation Evidence (required)

Commands and result summary:

ARCHON_HOME=$(mktemp -d) bun run validate

Result: passed. This ran bundled-default checks, type-check, lint with --max-warnings 0, format check, and the per-package isolated test suite.

Additional targeted checks run during development:

bun test packages/providers/src/skills.test.ts
bun test packages/providers/src/codex/provider.test.ts
bun test packages/workflows/src/validator.test.ts
bun test packages/core/src/config/config-loader.test.ts
ARCHON_HOME=$(mktemp -d) bun test packages/workflows/src/dag-executor.test.ts

Real Archon workflow E2E skill smokes:

0cfc3bee6be6fc5cef42cff370d628ac  e2e-codex-skill-explicit-smoke
  PASS: Codex loaded explicit /tmp/.../SKILL.md via workflow skills:
  returned ARCHON_E2E_EXPLICIT_SKILL_20260502

6dbe0c731e4dad5f4dffb0e15401b7a1  e2e-codex-skill-name-smoke
  PASS: Codex resolved archon-e2e-global-skill from ~/.codex/skills
  returned ARCHON_E2E_GLOBAL_SKILL_20260502

72b0fbbb505c2e1ec8b5847b76285f48  e2e-codex-dollar-skill-smoke
  PASS: native Codex $skill discovery still works inside an Archon workflow
  returned ARCHON_E2E_DOLLAR_SKILL_20260502
  • Evidence provided: tests plus real workflow run IDs and sentinel outputs from Codex.
  • If any command is intentionally skipped, explain why: none.

Security Impact (required)

  • New permissions/capabilities? Yes
  • New external network calls? No
  • Secrets/tokens handling changed? No
  • File system access scope changed? Yes

Codex nodes can now explicitly load local SKILL.md files selected by workflow skills:. The file read scope is limited to explicit skill path refs and documented skill roots, with validation errors for missing or unreadable skills. The resolver now fails fast when a higher-precedence candidate exists but cannot be read, avoiding silent fallback to unintended lower-precedence instructions.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? Yes
  • Database migration needed? No

Existing workflows without skills: are unchanged. assistants.codex.skillRoots is optional; default roots still work. No upgrade steps are required unless a user wants custom skill roots:

assistants:
  codex:
    skillRoots:
      - ./.codex/skills
      - ~/.codex/skills

Human Verification (required)

What was personally validated beyond CI:

  • Verified scenarios:
    • workflow-declared skills: using an explicit absolute skill directory;
    • workflow-declared skills: using a skill name resolved from ~/.codex/skills;
    • native Codex $skill discovery inside an Archon workflow;
    • missing skill validation emits actionable searched paths.
  • Edge cases checked:
    • blank skill refs are rejected by schema validation;
    • provider-specific validation does not let Pi pass on Codex-only .codex/skills roots;
    • unreadable higher-precedence skill candidates stop resolution instead of silently falling through.
  • What was not verified:
    • live Pi skill runtime success, because local Pi auth/API key for minimax/MiniMax-M2.7 was unavailable; validation did reach skillCount: 1 / missingSkillCount: 0 before provider auth failure.

Side Effects / Blast Radius (required)

  • Affected subsystems/workflows: Codex provider execution, workflow validation, CLI workflow validation, config loading, docs, and provider capability metadata.
  • Potential unintended effects: workflows with invalid or unreadable skills now fail earlier instead of running without the expected instructions.
  • Guardrails/monitoring for early detection: validation errors include searched paths; Codex runtime logs codex.skills_loaded with loaded skill names and paths.

Rollback Plan (required)

  • Fast rollback command/path: revert the two commits on this branch.
  • Feature flags or config toggles (if any): none. Removing skills: from affected workflows restores prior Codex behavior for those nodes.
  • Observable failure symptoms: workflow validation errors for skills, or Codex responses missing expected skill-specific sentinel/behavior in smoke workflows.

Risks and Mitigations

  • Risk: local skill content can materially steer Codex behavior.
    • Mitigation: skills must be explicitly declared by workflow/config path or name, and validation fails on missing/unreadable candidates.
  • Risk: provider search roots diverge and validation drifts from runtime behavior.
    • Mitigation: provider-aware validation is covered by tests, including non-Codex root behavior.
  • Risk: docs imply broader support than a provider actually gives.
    • Mitigation: docs now call out provider-specific mechanics and link to the skills guide.

Summary by CodeRabbit

  • New Features

    • Skills support extended to Codex and Pi providers (in addition to Claude)
    • New configurable skill root directories for custom skill locations
    • Enhanced workflow skill validation with multi-provider support
  • Documentation

    • Updated guides and references to document skills support across Claude, Codex, and Pi
  • Tests

    • Added comprehensive test coverage for skill resolution and validation

borshyo added 2 commits May 2, 2026 12:44
Fixes applied:
- Align workflow skill validation with provider-specific resolution
- Fail skill resolution on unreadable high-precedence candidates
- Update workflow docs for Codex/Pi skills support

Tests added:
- Provider resolver unreadable/provider-root coverage
- Workflow validator provider-specific skill coverage
- CLI validate Codex skillRoots integration coverage

Skipped (see review artifacts):
- GitHub PR comment: no PR exists for this branch

Review artifacts: /Users/kirill/.archon/workspaces/borshyo/Archon/artifacts/runs/9e81ffba134e9eb4d500dbb810a4f22d/review/
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

📝 Walkthrough

Walkthrough

This PR extends skill support from Claude-only to cross-provider functionality. It introduces a new skill resolution module, enables Codex skills capability, adds skillRoots configuration to Codex and workflow configs, updates workflow skill validation to use provider-driven resolution, and expands documentation and tests to cover Codex and Pi providers.

Changes

Cross-Provider Skills Support

Layer / File(s) Summary
Core Types & Utility Module
packages/providers/src/skills.ts, packages/providers/src/types.ts, packages/providers/package.json
New skills.ts module exports skill resolution functions (resolveSkillReferences, resolveProviderSkillReferences, loadResolvedSkills, formatMissingSkills) and types (SkillResolutionOptions, SkillResolutionResult, ResolvedSkill, MissingSkill, LoadedSkill). CodexProviderDefaults adds optional skillRoots?: string[] field. Package exports ./skills subpath.
Provider Configuration & Parsing
packages/providers/src/codex/config.ts, packages/workflows/src/deps.ts, packages/core/src/config/config-loader.ts, packages/core/src/config/config-loader.test.ts
Codex config parsing now accepts skillRoots array. WorkflowConfig.assistants.codex adds optional skillRoots field. Config loader template documents skillRoots example. Tests verify skillRoots merging and sanitization in safe config output.
Provider Capability & Implementation
packages/providers/src/codex/capabilities.ts, packages/providers/src/codex/provider.ts, packages/providers/src/codex/provider.test.ts, packages/providers/src/community/pi/options-translator.ts
Codex capabilities enable skills: true. Codex provider implements skill injection: resolves skill references, loads resolved skills, prepends formatted skill context to prompt before streaming. Pi provider refactored to use centralized getAgentSkillRoots(). Tests verify skill resolution, prompt augmentation, logging, and error handling.
Provider Index & Registry
packages/providers/src/index.ts, packages/providers/src/registry.test.ts
Re-exports skill utilities and types from ./skills. Registry tests verify Codex capabilities report skills: true.
Workflow Validation & Configuration
packages/workflows/src/validator.ts, packages/workflows/src/validator.test.ts, packages/workflows/src/schemas/dag-node.ts
ValidationConfig adds optional skillRootsByProvider map. Validator rewritten to use provider-driven resolveProviderSkillReferences() instead of hardcoded Claude paths; skips non-skill-capable providers early. Schema trims whitespace from skill strings. Tests cover default-root resolution, provider-specific roots, and missing-skill errors with hints.
Workflow Executor & Dependencies
packages/workflows/src/dag-executor.test.ts, packages/workflows/src/deps.ts, packages/workflows/src/loader.test.ts
Executor tests mock workflow path helpers and update Codex capability expectations. Loader tests isolate ARCHON_HOME per test. Executor assertions verify no unsupported-capability warnings for Codex skills.
CLI Command Integration & Tests
packages/cli/src/commands/validate.ts, packages/cli/src/commands/validate.test.ts, packages/cli/package.json
CLI validateWorkflowsCommand derives skillRootsByProvider from merged config and passes it to validator. New test scaffolds temporary repos with custom Codex skill roots, validates workflows, and asserts zero errors.
Documentation
packages/docs-web/src/content/docs/book/quick-reference.md, packages/docs-web/src/content/docs/guides/authoring-workflows.md, packages/docs-web/src/content/docs/guides/index.md, packages/docs-web/src/content/docs/guides/skills.md
Quick reference, authoring guide, and navigation updated to reflect cross-provider skills support (Claude, Codex, Pi). Skills guide expanded with provider-specific mechanics, default/custom discovery locations, installation instructions, configuration examples, and revised troubleshooting.

Sequence Diagram

sequenceDiagram
    participant User as User/<br/>CLI
    participant Config as Config<br/>Loader
    participant Validator as Workflow<br/>Validator
    participant Provider as Codex<br/>Provider
    participant Skills as Skills<br/>Resolver

    User->>Config: Load merged config<br/>(repo + global)
    Config-->>User: Codex skillRoots,<br/>assistants config
    User->>Validator: validateWorkflowsCommand<br/>(skillRootsByProvider)
    
    Validator->>Validator: For each workflow node
    alt Node has skills
        Validator->>Skills: resolveProviderSkillReferences<br/>(provider, skillRefs,<br/>skillRootsByProvider)
        Skills-->>Validator: resolved skills ∪<br/>missing skills
        alt Missing skills exist
            Validator->>Validator: Report errors
        else All skills resolved
            Validator->>Validator: Continue validation ✓
        end
    end

    Note over User,Validator: Validation complete
    
    User->>Provider: sendQuery(node.skills)
    Provider->>Skills: resolveSkillReferences<br/>(skillRefs, skillRoots)
    Skills-->>Provider: resolved + loaded skills
    Provider->>Provider: Build skill context<br/>from frontmatter
    Provider->>Provider: Prepend skills to prompt
    Provider-->>User: Stream response<br/>(with skill context)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 Hop, hop! Cross-provider skills now bloom,
Codex and Pi escape the Claude-only room,
Root paths configured, frontmatter parsed with care,
Prompts enriched with knowledge everywhere!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(codex): support workflow skills' accurately captures the main feature addition—enabling Codex workflow nodes to explicitly preload Archon skills.
Description check ✅ Passed The description comprehensively covers all required template sections: Summary (with bullets), UX Journey (Before/After), Architecture Diagram with connection inventory, labels, metadata, validation evidence with specific test runs and E2E smoke results, security/compatibility analysis, human verification of scenarios and edge cases, side effects, and rollback plan.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 466702dfc7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -86,6 +104,7 @@ export async function validateWorkflowsCommand(
): Promise<number> {
const config = await buildValidationConfig(cwd);
const mergedConfig = await loadConfig(cwd);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle loadConfig errors before workflow validation

validateWorkflowsCommand now awaits loadConfig(cwd) without a fallback, so a malformed or unreadable global/repo config causes the command to throw before discovery/validation runs. This regresses prior behavior where config-load failures were tolerated (via discoverWorkflowsWithConfig’s internal try/catch) and users could still validate workflows with defaults.

Useful? React with 👍 / 👎.

function expandRoot(root: string, cwd: string): string {
const home = getHomeDir();
if (root === '~') return home;
if (root.startsWith(`~${sep}`)) return join(home, root.slice(2));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Expand '~/…' skill roots regardless of platform separator

The tilde expansion only matches ~${sep}. On Windows, sep is \, so config values written as ~/.codex/skills (common in docs and cross-platform configs) are treated as relative paths instead of home-relative roots. That makes skill resolution/validation miss configured roots on Windows hosts unless users rewrite paths with backslashes.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/workflows/src/validator.ts (1)

414-422: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not skip the rest of node validation when skills are unsupported.

Line 421 uses continue, which skips subsequent checks (hooks/agents/tool restrictions/script validation) for the same node. Only skills resolution should be skipped.

Suggested fix
       if (provider && isRegisteredProvider(provider)) {
         const caps = getProviderCapabilities(provider);
         if (!caps.skills) {
           issues.push({
             level: 'warning',
             nodeId: node.id,
             field: 'skills',
             message: `Skills are not supported by provider '${provider}' — this will be ignored`,
             hint: 'Remove the skills field or switch to a provider that supports skills',
           });
-          continue;
+        } else {
+          const skillRoots = provider ? config?.skillRootsByProvider?.[provider] : undefined;
+          const skillResolution = await resolveProviderSkillReferences(provider, cwd, node.skills, {
+            skillRoots,
+          });
+          for (const missingSkill of skillResolution.missing) {
+            const reason = missingSkill.reason ? `${missingSkill.reason}\n` : '';
+            issues.push({
+              level: 'error',
+              nodeId: node.id,
+              field: 'skills',
+              message: `Skill '${missingSkill.ref}' not found or not readable`,
+              hint: `${reason}Searched:\n${missingSkill.searchedPaths.map(path => `  - ${path}`).join('\n')}`,
+            });
+          }
         }
-      }
-
-      const skillRoots = provider ? config?.skillRootsByProvider?.[provider] : undefined;
-      const skillResolution = await resolveProviderSkillReferences(provider, cwd, node.skills, {
-        skillRoots,
-      });
-      for (const missingSkill of skillResolution.missing) {
-        const reason = missingSkill.reason ? `${missingSkill.reason}\n` : '';
-        issues.push({
-          level: 'error',
-          nodeId: node.id,
-          field: 'skills',
-          message: `Skill '${missingSkill.ref}' not found or not readable`,
-          hint: `${reason}Searched:\n${missingSkill.searchedPaths.map(path => `  - ${path}`).join('\n')}`,
-        });
-      }
+      } else {
+        const skillRoots = provider ? config?.skillRootsByProvider?.[provider] : undefined;
+        const skillResolution = await resolveProviderSkillReferences(provider, cwd, node.skills, {
+          skillRoots,
+        });
+        for (const missingSkill of skillResolution.missing) {
+          const reason = missingSkill.reason ? `${missingSkill.reason}\n` : '';
+          issues.push({
+            level: 'error',
+            nodeId: node.id,
+            field: 'skills',
+            message: `Skill '${missingSkill.ref}' not found or not readable`,
+            hint: `${reason}Searched:\n${missingSkill.searchedPaths.map(path => `  - ${path}`).join('\n')}`,
+          });
+        }
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/workflows/src/validator.ts` around lines 414 - 422, The code
currently pushes a warning about unsupported skills and then does a bare
`continue`, which skips all further validation for that node
(hooks/agents/tool/script checks); remove the `continue` and instead only bypass
the skills-resolution step: keep the warning push for provider/skills
(referencing provider and node.id) but ensure subsequent validation logic
(hooks, agents, tool restrictions, script validation) still runs for the same
node; if there is a separate skills resolution call, gate only that call on
provider support rather than skipping the entire node validation.
🧹 Nitpick comments (1)
packages/cli/package.json (1)

11-11: Isolate validate.test.ts from the other CLI suites.

This test calls clearConfigCache(), which mutates module-level state, alongside mutations to process.env.ARCHON_HOME and DEFAULT_AI_ASSISTANT. Running it together with other test files in the same bun test invocation risks cross-file interference if the cache state is not fully isolated between files.

🔎 Suggested fix
-    "test": "bun test src/commands/version.test.ts src/commands/setup.test.ts src/commands/skill.test.ts src/commands/validate.test.ts && bun test src/commands/workflow.test.ts && bun test src/commands/isolation.test.ts && bun test src/commands/chat.test.ts && bun test src/commands/serve.test.ts",
+    "test": "bun test src/commands/version.test.ts src/commands/setup.test.ts src/commands/skill.test.ts && bun test src/commands/validate.test.ts && bun test src/commands/workflow.test.ts && bun test src/commands/isolation.test.ts && bun test src/commands/chat.test.ts && bun test src/commands/serve.test.ts",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/package.json` at line 11, The test runner groups
validate.test.ts with other CLI tests and that file calls clearConfigCache() and
mutates process.env (e.g., DEFAULT_AI_ASSISTANT, ARCHON_HOME), so change the
"test" script in package.json to run validate.test.ts in a separate bun test
invocation: remove src/commands/validate.test.ts from the grouped bun test call
and add an independent && bun test src/commands/validate.test.ts (so
clearConfigCache and env mutations run in their own process). This targets the
test script and the specific file name validate.test.ts and the implicated
function clearConfigCache() and environment variables to avoid cross-file state
leakage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/docs-web/src/content/docs/guides/skills.md`:
- Around line 128-131: Replace the anonymous fenced code block containing the
directory tree snippet (the triple-backticks block showing
".agents/skills/my-skill/ └── SKILL.md") with a language-labeled fence by adding
"text" (or "plaintext") after the opening backticks so the fence becomes
```text, which will satisfy MD040 in CI.

In `@packages/providers/src/codex/config.ts`:
- Around line 41-43: When building result.skillRoots from raw.skillRoots (the
Array.isArray branch for raw.skillRoots), trim each string and filter out
entries that are not strings or that are empty after trimming so whitespace-only
values are dropped; update the predicate used when populating result.skillRoots
(referencing raw.skillRoots and result.skillRoots) to map/trim values and only
keep non-empty trimmed strings before assigning to result.skillRoots.

In `@packages/providers/src/codex/provider.ts`:
- Around line 96-100: The prompt builder buildCodexSkillContext currently
injects skill.skillPath into model input and elsewhere full paths are logged;
remove any use of skill.skillPath in prompts and replace with non-sensitive
identifiers (e.g., skill.name and an index or truncated/sanitized ID) so only
name/count are sent to the model; update corresponding info logs that currently
print skill.skillPath to instead log either path.basename(skill.skillPath), a
relative/sanitized identifier, or redact the path entirely; also scan and update
other locations that log or send skill.skillPath (notably the other usages
referenced around the same module) to use the same sanitized identifier
approach.

In `@packages/workflows/src/schemas/dag-node.ts`:
- Around line 147-150: The schema now treats the field skills as a validated
first-class property but the constant LOOP_NODE_AI_FIELDS still lists "skills"
as an unsupported/ignored field, causing loop nodes to drop or warn about
skills; remove "skills" from the LOOP_NODE_AI_FIELDS set/array (or update the
logic that builds that list) so loop-node handling no longer treats skills as
unsupported, and run/update any tests that assert supported fields for the loop
node (references: skills and LOOP_NODE_AI_FIELDS).

---

Outside diff comments:
In `@packages/workflows/src/validator.ts`:
- Around line 414-422: The code currently pushes a warning about unsupported
skills and then does a bare `continue`, which skips all further validation for
that node (hooks/agents/tool/script checks); remove the `continue` and instead
only bypass the skills-resolution step: keep the warning push for
provider/skills (referencing provider and node.id) but ensure subsequent
validation logic (hooks, agents, tool restrictions, script validation) still
runs for the same node; if there is a separate skills resolution call, gate only
that call on provider support rather than skipping the entire node validation.

---

Nitpick comments:
In `@packages/cli/package.json`:
- Line 11: The test runner groups validate.test.ts with other CLI tests and that
file calls clearConfigCache() and mutates process.env (e.g.,
DEFAULT_AI_ASSISTANT, ARCHON_HOME), so change the "test" script in package.json
to run validate.test.ts in a separate bun test invocation: remove
src/commands/validate.test.ts from the grouped bun test call and add an
independent && bun test src/commands/validate.test.ts (so clearConfigCache and
env mutations run in their own process). This targets the test script and the
specific file name validate.test.ts and the implicated function
clearConfigCache() and environment variables to avoid cross-file state leakage.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: e20e1991-068b-4637-a84f-bd883e986d63

📥 Commits

Reviewing files that changed from the base of the PR and between 69b2c89 and 466702d.

📒 Files selected for processing (26)
  • packages/cli/package.json
  • packages/cli/src/commands/validate.test.ts
  • packages/cli/src/commands/validate.ts
  • packages/core/src/config/config-loader.test.ts
  • packages/core/src/config/config-loader.ts
  • packages/docs-web/src/content/docs/book/quick-reference.md
  • packages/docs-web/src/content/docs/guides/authoring-workflows.md
  • packages/docs-web/src/content/docs/guides/index.md
  • packages/docs-web/src/content/docs/guides/skills.md
  • packages/providers/package.json
  • packages/providers/src/codex/capabilities.ts
  • packages/providers/src/codex/config.ts
  • packages/providers/src/codex/provider.test.ts
  • packages/providers/src/codex/provider.ts
  • packages/providers/src/community/pi/options-translator.ts
  • packages/providers/src/index.ts
  • packages/providers/src/registry.test.ts
  • packages/providers/src/skills.test.ts
  • packages/providers/src/skills.ts
  • packages/providers/src/types.ts
  • packages/workflows/src/dag-executor.test.ts
  • packages/workflows/src/deps.ts
  • packages/workflows/src/loader.test.ts
  • packages/workflows/src/schemas/dag-node.ts
  • packages/workflows/src/validator.test.ts
  • packages/workflows/src/validator.ts

Comment on lines 128 to 131
```
.claude/skills/my-skill/
.agents/skills/my-skill/
└── SKILL.md
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language tag to the directory-tree fence.

The anonymous fence at Line 128 will keep tripping MD040 in docs CI. Mark it as text/plaintext so the lint warning goes away.

♻️ Proposed fix
-```
+```text
 .agents/skills/my-skill/
 └── SKILL.md
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 128-128: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/docs-web/src/content/docs/guides/skills.md` around lines 128 - 131,
Replace the anonymous fenced code block containing the directory tree snippet
(the triple-backticks block showing ".agents/skills/my-skill/ └── SKILL.md")
with a language-labeled fence by adding "text" (or "plaintext") after the
opening backticks so the fence becomes ```text, which will satisfy MD040 in CI.

Comment on lines +41 to +43
if (Array.isArray(raw.skillRoots)) {
result.skillRoots = raw.skillRoots.filter((d): d is string => typeof d === 'string');
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Trim and drop empty skillRoots entries before storing them.

Right now any whitespace-only string survives parsing and can reach skill resolution as a real root. That makes config typos behave like valid search roots instead of being ignored.

🛠️ Suggested fix
   if (Array.isArray(raw.skillRoots)) {
-    result.skillRoots = raw.skillRoots.filter((d): d is string => typeof d === 'string');
+    result.skillRoots = raw.skillRoots
+      .filter((d): d is string => typeof d === 'string')
+      .map(root => root.trim())
+      .filter(root => root.length > 0);
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (Array.isArray(raw.skillRoots)) {
result.skillRoots = raw.skillRoots.filter((d): d is string => typeof d === 'string');
}
if (Array.isArray(raw.skillRoots)) {
result.skillRoots = raw.skillRoots
.filter((d): d is string => typeof d === 'string')
.map(root => root.trim())
.filter(root => root.length > 0);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/providers/src/codex/config.ts` around lines 41 - 43, When building
result.skillRoots from raw.skillRoots (the Array.isArray branch for
raw.skillRoots), trim each string and filter out entries that are not strings or
that are empty after trimming so whitespace-only values are dropped; update the
predicate used when populating result.skillRoots (referencing raw.skillRoots and
result.skillRoots) to map/trim values and only keep non-empty trimmed strings
before assigning to result.skillRoots.

Comment on lines +96 to +100
function buildCodexSkillContext(skills: readonly LoadedSkill[]): string {
const blocks = skills.map(
skill =>
`--- BEGIN SKILL ${skill.name} (${skill.skillPath}) ---\n${skill.content.trim()}\n--- END SKILL ${skill.name} ---`
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid exposing absolute skill paths in prompts and info logs.

This currently sends skill.skillPath to the model and logs full paths at info; both can leak usernames/repo layout. Keep names (and maybe count) only, or log sanitized relative identifiers.

Suggested hardening diff
-      `--- BEGIN SKILL ${skill.name} (${skill.skillPath}) ---\n${skill.content.trim()}\n--- END SKILL ${skill.name} ---`
+      `--- BEGIN SKILL ${skill.name} ---\n${skill.content.trim()}\n--- END SKILL ${skill.name} ---`
       getLog().info(
         {
           skills: loadedSkills.map(skill => skill.name),
-          skillPaths: loadedSkills.map(skill => skill.skillPath),
+          skillCount: loadedSkills.length,
         },
         'codex.skills_loaded'
       );
As per coding guidelines, "Include context in logs ... never log API keys, tokens ... or PII."

Also applies to: 585-589

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/providers/src/codex/provider.ts` around lines 96 - 100, The prompt
builder buildCodexSkillContext currently injects skill.skillPath into model
input and elsewhere full paths are logged; remove any use of skill.skillPath in
prompts and replace with non-sensitive identifiers (e.g., skill.name and an
index or truncated/sanitized ID) so only name/count are sent to the model;
update corresponding info logs that currently print skill.skillPath to instead
log either path.basename(skill.skillPath), a relative/sanitized identifier, or
redact the path entirely; also scan and update other locations that log or send
skill.skillPath (notably the other usages referenced around the same module) to
use the same sanitized identifier approach.

Comment on lines 147 to 150
skills: z
.array(z.string().min(1, 'each skill must be a non-empty string'))
.array(z.string().trim().min(1, 'each skill must be a non-empty string'))
.nonempty("'skills' must be a non-empty array")
.optional(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't keep skills in the loop-node ignore list.

This change makes skills a first-class validated field, but LOOP_NODE_AI_FIELDS later in this file still treats it as unsupported. Loop nodes will keep warning or dropping skills, which breaks the new provider-agnostic behavior.

🔧 Suggested fix
 export const LOOP_NODE_AI_FIELDS: readonly string[] = BASH_NODE_AI_FIELDS.filter(
-  f => f !== 'model' && f !== 'provider'
+  f => f !== 'model' && f !== 'provider' && f !== 'skills'
 );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/workflows/src/schemas/dag-node.ts` around lines 147 - 150, The
schema now treats the field skills as a validated first-class property but the
constant LOOP_NODE_AI_FIELDS still lists "skills" as an unsupported/ignored
field, causing loop nodes to drop or warn about skills; remove "skills" from the
LOOP_NODE_AI_FIELDS set/array (or update the logic that builds that list) so
loop-node handling no longer treats skills as unsupported, and run/update any
tests that assert supported fields for the loop node (references: skills and
LOOP_NODE_AI_FIELDS).

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.

1 participant