feat: add deepagents-cli support - #1359
Conversation
|
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. |
|
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:
Happy to go whichever route works best for you. Let me know! |
| }; | ||
|
|
||
| return new RulesyncSubagent({ | ||
| baseDir: ".", // RulesyncSubagent baseDir is always the project root directory. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
deepagentsas 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.jsonflat-array converter), skills, and subagents. - Update README, cspell, gitignore registry/tests, and repository
.gitignoreentries 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). |
| 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, | ||
| }); | ||
| } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
| validate: false, | ||
| }), | ||
| ).not.toThrow(); |
There was a problem hiding this comment.
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.
| validate: false, | |
| }), | |
| ).not.toThrow(); | |
| validate: true, | |
| }), | |
| ).toThrow(); |
There was a problem hiding this comment.
Fixed — renamed to "should not throw on invalid frontmatter when validate=false" to accurately describe what the test asserts. 051ca35.
| for (const def of definitions) { | ||
| if (def.type === "prompt") continue; | ||
| if (!def.command) continue; | ||
|
|
||
| entries.push({ | ||
| command: ["bash", "-c", def.command], | ||
| events: [deepagentsEvent], | ||
| }); |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
Fixed — added if (def.matcher) continue; to skip matcher-based definitions, consistent with supportsMatcher: false in the processor registration. 051ca35.
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>
051ca35 to
3934c02
Compare
|
@awg66 Thank you! |
…gs-deepagents fix: address review findings from PR #1359 (deepagents-cli)
Summary
Adds support for deepagents-cli (terminal coding agent by LangChain) across all five rulesync features.
.deepagents/AGENTS.md(root rule) and.deepagents/memories/*.md(non-root rules).deepagents/.mcp.json— samemcpServersformat as Claude Code; supports project + global scope.deepagents/hooks.json(global-only) — flat array format{"hooks": [{"command": ["bash", "-c", "..."], "events": ["session.start"]}]}with full canonical↔deepagents bidirectional conversion.deepagents/skills/<name>/SKILL.mdwithname,description,allowed-toolsfrontmatter.deepagents/agents/<name>.mdwithname,description,modelfrontmatterImplementation notes
tool-hooks-converter.ts) due to deepagents' fundamentally different flat-array format vs the event-keyed object format used by other tools["bash", "-c", commandString]to avoid shell parsing issuesDEEPAGENTS_HOOK_EVENTS,CANONICAL_TO_DEEPAGENTS_EVENT_NAMES, andDEEPAGENTS_TO_CANONICAL_EVENT_NAMESmappings inhooks.tshooks-processor.tsto filter project targets bysupportsProject: true, so global-only tools (like deepagents hooks) are excluded from project-mode generationdeepagentstool-specific override section support inHooksConfigSchemaTest plan
pnpm test— 4489 tests)"deepagents"in expected target setspnpm buildcompiles cleanly with no TypeScript errorsCloses #1357
🤖 Generated with Claude Code