Skip to content

feat: add deepagents-cli support - #1359

Merged
dyoshikawa merged 5 commits into
dyoshikawa:mainfrom
awg66:feat/deepagents-cli-support
Mar 23, 2026
Merged

feat: add deepagents-cli support#1359
dyoshikawa merged 5 commits into
dyoshikawa:mainfrom
awg66:feat/deepagents-cli-support

Conversation

@awg66

@awg66 awg66 commented Mar 22, 2026

Copy link
Copy Markdown

Summary

Adds support for deepagents-cli (terminal coding agent by LangChain) across all five rulesync features.

  • Rules: .deepagents/AGENTS.md (root rule) and .deepagents/memories/*.md (non-root rules)
  • MCP: .deepagents/.mcp.json — same mcpServers format as Claude Code; supports project + global scope
  • Hooks: .deepagents/hooks.json (global-only) — flat array format {"hooks": [{"command": ["bash", "-c", "..."], "events": ["session.start"]}]} with full canonical↔deepagents bidirectional conversion
  • Skills: .deepagents/skills/<name>/SKILL.md with name, description, allowed-tools frontmatter
  • Subagents: .deepagents/agents/<name>.md with name, description, model frontmatter

Implementation notes

  • Hooks use a custom converter (bypasses tool-hooks-converter.ts) due to deepagents' fundamentally different flat-array format vs the event-keyed object format used by other tools
  • Single-string commands are wrapped as ["bash", "-c", commandString] to avoid shell parsing issues
  • Added DEEPAGENTS_HOOK_EVENTS, CANONICAL_TO_DEEPAGENTS_EVENT_NAMES, and DEEPAGENTS_TO_CANONICAL_EVENT_NAMES mappings in hooks.ts
  • Fixed hooks-processor.ts to filter project targets by supportsProject: true, so global-only tools (like deepagents hooks) are excluded from project-mode generation
  • Adds deepagents tool-specific override section support in HooksConfigSchema

Test plan

  • All existing tests continue to pass (pnpm test — 4489 tests)
  • New unit tests for each feature class (rules, MCP, hooks, skills, subagents)
  • Processor tests updated to include "deepagents" in expected target sets
  • pnpm build compiles cleanly with no TypeScript errors

Closes #1357

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution! Unfortunately, this PR has 1839 added lines, which exceeds the limit of 1000 lines for external contributors.

Please split your changes into smaller PRs. See CONTRIBUTING.md for details.

@awg66

awg66 commented Mar 22, 2026

Copy link
Copy Markdown
Author

Hi @dyoshikawa! The CI check flagged this PR for exceeding the 1,000-line addition limit — the implementation spans 5 features (rules, MCP, hooks, skills, subagents) plus tests, which puts it at ~1,839 lines.

A few options I can think of:

  1. Split into smaller PRs — I can restructure into 3 sequential PRs (~500–700 lines each), though it would take a few merge cycles to land everything.
  2. Collaborator access — if you'd be comfortable granting collaborator access, the line limit check would be bypassed and this PR could land as-is.
  3. You merge directly — if you're happy with the implementation, you could pull the branch and merge it yourself.

Happy to go whichever route works best for you. Let me know!

@dyoshikawa dyoshikawa left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Reviewed findings #2 (README scope) and #3 (hardcoded baseDir). After re-checking the README table columns against processor settings, the scope indicators actually match correctly — so #2 was a false positive. Posting only the comment for #3 below.

};

return new RulesyncSubagent({
baseDir: ".", // RulesyncSubagent baseDir is always the project root directory.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Other subagent implementations (e.g. ClaudecodeSubagent, CodexCliSubagent) use this.getBaseDir() or this.baseDir here. Hardcoding "." means this would produce incorrect results if the class is ever instantiated with a non-default baseDir. Was this intentional, or should it follow the same pattern as the others?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch — fixed to use this.getBaseDir(). The comment was misleading; it was a copy from claudecode-subagent.ts which also hardcodes ".", but using the actual baseDir is clearly the right behaviour. Updated in 051ca35.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new deepagents tool target to Rulesync, implementing deepagents-cli file formats and integrating them into the existing processors (rules, MCP, hooks, skills, subagents), plus updating documentation and ignore lists.

Changes:

  • Register deepagents as a supported tool target and wire it into the rules/mcp/hooks/skills/subagents processors.
  • Implement deepagents-specific adapters for rules (.deepagents/AGENTS.md + memories), MCP (.deepagents/.mcp.json), hooks (.deepagents/hooks.json flat-array converter), skills, and subagents.
  • Update README, cspell, gitignore registry/tests, and repository .gitignore entries for deepagents files.

Reviewed changes

Copilot reviewed 25 out of 26 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/types/tool-targets.ts Adds deepagents to the global tool target list.
src/types/tool-targets.test.ts Updates tool target snapshot/expectations to include deepagents.
src/types/hooks.ts Adds deepagents hook events and canonical↔deepagents event-name mappings; extends hooks config schema for deepagents overrides.
src/features/subagents/subagents-processor.ts Registers deepagents subagent factory and metadata.
src/features/subagents/subagents-processor.test.ts Updates expected target sets to include deepagents.
src/features/subagents/deepagents-subagent.ts Implements deepagents subagent frontmatter parsing and rulesync conversion.
src/features/subagents/deepagents-subagent.test.ts Adds unit tests for deepagents subagent behavior and conversions.
src/features/skills/skills-processor.ts Registers deepagents skill factory and metadata.
src/features/skills/skills-processor.test.ts Updates expected target sets to include deepagents.
src/features/skills/deepagents-skill.ts Implements deepagents skill directory handling and rulesync conversion.
src/features/skills/deepagents-skill.test.ts Adds unit tests for deepagents skills.
src/features/rules/rules-processor.ts Registers deepagents rules factory and metadata.
src/features/rules/deepagents-rule.ts Implements deepagents rule file paths and rulesync conversion.
src/features/rules/deepagents-rule.test.ts Adds unit tests for deepagents rules behavior.
src/features/mcp/mcp-processor.ts Registers deepagents MCP factory and metadata.
src/features/mcp/deepagents-mcp.ts Implements deepagents .mcp.json reading/writing and rulesync conversion.
src/features/mcp/deepagents-mcp.test.ts Adds unit tests for deepagents MCP behavior.
src/features/hooks/hooks-processor.ts Registers deepagents hooks factory and adjusts target filtering by supportsProject.
src/features/hooks/hooks-processor.test.ts Updates expected hook target sets (project/global/importOnly) to account for deepagents.
src/features/hooks/deepagents-hooks.ts Implements deepagents hooks flat-array format converter and rulesync conversion.
src/features/hooks/deepagents-hooks.test.ts Adds unit tests for deepagents hooks conversions (including overrides).
src/cli/commands/gitignore.test.ts Extends gitignore command expectations with deepagents entries.
src/cli/commands/gitignore-entries.ts Adds deepagents gitignore entry registry items.
cspell.json Adds deepagents to spelling dictionary.
README.md Documents deepagents-cli feature support matrix entry.
.gitignore Adds deepagents paths (and includes .copilot/mcp-config.json).

Comment on lines +108 to +152
toRulesyncSkill(): RulesyncSkill {
const frontmatter = this.getFrontmatter();
const rulesyncFrontmatter: RulesyncSkillFrontmatterInput = {
name: frontmatter.name,
description: frontmatter.description,
targets: ["*"],
};

return new RulesyncSkill({
baseDir: this.baseDir,
relativeDirPath: RULESYNC_SKILLS_RELATIVE_DIR_PATH,
dirName: this.getDirName(),
frontmatter: rulesyncFrontmatter,
body: this.getBody(),
otherFiles: this.getOtherFiles(),
validate: true,
global: this.global,
});
}

static fromRulesyncSkill({
baseDir = process.cwd(),
rulesyncSkill,
validate = true,
global = false,
}: ToolSkillFromRulesyncSkillParams): DeepagentsSkill {
const settablePaths = DeepagentsSkill.getSettablePaths({ global });
const rulesyncFrontmatter = rulesyncSkill.getFrontmatter();

const deepagentsFrontmatter: DeepagentsSkillFrontmatter = {
name: rulesyncFrontmatter.name,
description: rulesyncFrontmatter.description,
};

return new DeepagentsSkill({
baseDir,
relativeDirPath: settablePaths.relativeDirPath,
dirName: rulesyncSkill.getDirName(),
frontmatter: deepagentsFrontmatter,
body: rulesyncSkill.getBody(),
otherFiles: rulesyncSkill.getOtherFiles(),
validate,
global,
});
}

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

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

allowed-tools is parsed in DeepagentsSkillFrontmatterSchema, but it is never propagated into the canonical RulesyncSkill frontmatter (and it’s not read back in fromRulesyncSkill). This causes deepagents-specific configuration to be lost on tool→rulesync→tool roundtrips. Consider adding a deepagents tool-specific section to RulesyncSkillFrontmatterSchema/types (similar to opencode) and mapping allowed-tools into/out of that section here.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed — allowed-tools is now stored in a deepagents tool-specific section of RulesyncSkillFrontmatter (matching the pattern used by opencode), and read back in fromRulesyncSkill. Updated rulesync-skill.ts schema and types accordingly. 051ca35.

Comment on lines +75 to +77
validate: false,
}),
).not.toThrow();

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

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

This test case name and assertions don’t match: it says "should throw on invalid frontmatter when validate=true", but it constructs DeepagentsSkill with validate: false and asserts that it does not throw. Rename the test and/or adjust validate and the expectation so the test accurately documents the intended behavior.

Suggested change
validate: false,
}),
).not.toThrow();
validate: true,
}),
).toThrow();

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed — renamed to "should not throw on invalid frontmatter when validate=false" to accurately describe what the test asserts. 051ca35.

Comment on lines +63 to +70
for (const def of definitions) {
if (def.type === "prompt") continue;
if (!def.command) continue;

entries.push({
command: ["bash", "-c", def.command],
events: [deepagentsEvent],
});

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

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

HooksProcessor treats deepagents as supportsMatcher: false and logs "Skipped matcher hook(s)" when matchers are present, but canonicalToDeepagentsHooks currently still emits hook entries even when def.matcher is set (the matcher is silently dropped). To match the warning and avoid changing semantics, filter out definitions with matcher here (similar to canonicalToCopilotHooks).

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed — added if (def.matcher) continue; to skip matcher-based definitions, consistent with supportsMatcher: false in the processor registration. 051ca35.

alex-gatto-wd and others added 5 commits March 23, 2026 01:38
Adds support for deepagents-cli (by LangChain) across all five rulesync
features: rules, MCP, hooks, skills, and subagents.

- Rules: `.deepagents/AGENTS.md` (root) and `.deepagents/memories/*.md` (non-root)
- MCP: `.deepagents/.mcp.json` (project + global), same mcpServers format as Claude Code
- Hooks: `.deepagents/hooks.json` (global-only), flat array format with custom
  canonical↔deepagents conversion and bash-c command wrapping
- Skills: `.deepagents/skills/<name>/SKILL.md` with name/description/allowed-tools frontmatter
- Subagents: `.deepagents/agents/<name>.md` with name/description/model frontmatter

Adds DEEPAGENTS_HOOK_EVENTS and bidirectional event name mappings in hooks.ts,
registers "deepagents" in ALL_TOOL_TARGETS, and fixes hooks-processor to filter
project targets by supportsProject so global-only tools are excluded.

Closes dyoshikawa#1357

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add deepagents entries to gitignore.test.ts
- Add deepagents-cli row to README Supported Tools table
- Run pnpm dev gitignore to update project .gitignore
- Add "deepagents" to cspell word list
- Fix eslint no-type-assertion warnings with disable comments
- Fix formatting issues flagged by oxfmt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add comment to canonicalToDeepagentsHooks documenting the internal
  deepagents.hooks override merge vs. the processor's own merge path
- Add explanatory comment on baseDir: "." in toRulesyncSubagent
- Add toRulesyncSubagent tests covering name/body round-trip and
  model storage in deepagents tool-specific section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Restructure isDeepagentsHooksFile to use early return with TypeScript's
  "in" operator narrowing, eliminating the cast to { hooks: unknown }
- Remove cast on rulesyncFrontmatter.deepagents since RulesyncSubagentFrontmatter
  already types tool-specific sections as Record<string, unknown> | undefined

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use this.getBaseDir() in toRulesyncSubagent instead of hardcoded "."
- Round-trip allowed-tools through deepagents tool-specific section in
  RulesyncSkill so it survives tool→rulesync→tool conversions
- Fix inverted test name: "should not throw...when validate=false"
- Filter out matcher-based hook definitions in canonicalToDeepagentsHooks
  to match the supportsMatcher: false processor registration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@awg66
awg66 force-pushed the feat/deepagents-cli-support branch from 051ca35 to 3934c02 Compare March 23, 2026 05:38
@dyoshikawa
dyoshikawa merged commit fc75da8 into dyoshikawa:main Mar 23, 2026
6 checks passed
@dyoshikawa

Copy link
Copy Markdown
Owner

@awg66 Thank you!

@awg66
awg66 deleted the feat/deepagents-cli-support branch March 23, 2026 14:09
@github-actions github-actions Bot mentioned this pull request Mar 25, 2026
2 tasks
dyoshikawa added a commit that referenced this pull request Apr 3, 2026
…gs-deepagents

fix: address review findings from PR #1359 (deepagents-cli)
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.

feat: add support for deepagents-cli

4 participants