Skip to content

feat: add nested-glob target type for monorepo/multi-module AGENTS.md discovery - #234

Merged
yacosta738 merged 6 commits into
mainfrom
copilot/support-nested-agents-md-files
Mar 22, 2026
Merged

feat: add nested-glob target type for monorepo/multi-module AGENTS.md discovery#234
yacosta738 merged 6 commits into
mainfrom
copilot/support-nested-agents-md-files

Conversation

Copilot AI commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

AgentSync only supported a single flat AGENTS.md source per agent config, making it unusable for monorepos and multi-module projects where subdirectories carry domain-specific agent instructions.

New nested-glob target type

Recursively discovers files matching a glob pattern under a search root and creates a symlink for each match using a destination template.

[agents.claude.targets.nested]
source  = "."                             # search root (relative to project root)
pattern = "**/AGENTS.md"                  # recursive glob; ** crosses directory boundaries
exclude = [".agents/**", "node_modules/**", "**/target/**", "**/build/**"]
destination = "{relative_path}/CLAUDE.md" # template expanded per discovered file
type    = "nested-glob"

Given clients/agent-runtime/AGENTS.md and modules/core-kmp/AGENTS.md, this produces:

  • clients/agent-runtime/CLAUDE.md → symlink
  • modules/core-kmp/CLAUDE.md → symlink

Destination template placeholders

Placeholder Example Notes
{relative_path} clients/agent-runtime parent dir relative to source; . at search root
{file_name} AGENTS.md
{stem} AGENTS
{ext} md

Implementation details

  • config.rs: new SyncType::NestedGlob variant; new exclude: Vec<String> field on TargetConfig; all_gitignore_entries() skips NestedGlob destinations (they are templates, not literal paths)
  • linker.rs: process_nested_glob() walks with walkdir (follow_links = false); matches_path_glob() / path_glob_match() implement ** multi-segment glob matching on top of the existing single-segment matches_pattern(); expand_destination_template() handles placeholder substitution; clean() extended to re-discover and remove nested-glob symlinks
  • 13 new unit tests covering discovery, exclusion, dry-run, clean, and missing search root
Original prompt

This section details on the original issue you should resolve

<issue_title>Support for Nested AGENTS.md Files</issue_title>
<issue_description># Feature Request: Support for Nested AGENTS.md Files

Problem Statement

Currently, AgentSync only supports a single AGENTS.md source file in .agents/.
There is no mechanism to discover or sync AGENTS.md files that exist in
subdirectories of a project.

This limits AgentSync's usefulness in monorepos and multi-module projects
where different directories may need domain-specific agent instructions.

Use Cases

1. Monorepo with Domain-Specific Instructions

project-root/
├── .agents/
│   ├── AGENTS.md          # Root instructions (general)
│   └── agentsync.toml
├── clients/
│   └── agent-runtime/
│       └── AGENTS.md      # Rust-specific instructions
├── web/
│   └── apps/
│       └── dashboard/
│           └── AGENTS.md  # Vue/TypeScript-specific instructions
└── modules/
    └── core-kmp/
        └── AGENTS.md      # Kotlin-specific instructions

Each submodule has specialized instructions (Rust patterns, Vue conventions,
Kotlin patterns) that differ from the root. Currently, these nested
AGENTS.md files must be maintained manually or through external scripts.

2. Gradle Multi-Module Projects

android-app/
├── .agents/
│   └── AGENTS.md          # Android/Kotlin conventions
├── app/
│   └── AGENTS.md          # App-specific patterns
├── feature/
│   └── auth/
│       └── AGENTS.md      # Auth module patterns
└── core/
    └── AGENTS.md          # Core library patterns

3. Selective Inheritance

Many AI coding tools (Claude Code, OpenCode, etc.) already support reading
AGENTS.md from subdirectories
with inheritance/cascading behavior —
the closest AGENTS.md to the current working directory takes precedence.

AgentSync should complement this by:

  1. Discovering nested AGENTS.md files automatically
  2. Syncing them to each agent's expected location

Proposed Solutions

Option A: Glob-Based Discovery (Recommended)

Add support for glob patterns in agentsync.toml:

[agents.claude]
enabled = true

# Existing: single file
[agents.claude.targets.instructions]
source = "AGENTS.md"
destination = "CLAUDE.md"
type = "symlink"

# New: nested discovery
[agents.claude.targets.nested]
enabled = true
source_dir = "."          # Root of glob search
pattern = "**/AGENTS.md"   # Glob pattern
destination_template = "{relative_path}/AGENTS.md"
type = "symlink"

This would:

  • Discover all AGENTS.md files matching the pattern
  • Create symlinks maintaining the relative directory structure
  • For example: clients/agent-runtime/AGENTS.mdclients/agent-runtime/AGENTS.md (symlink)

Option B: Explicit Nested Targets

Keep the current flat structure but allow explicit per-directory targets:

[agents.claude]
enabled = true

[agents.claude.targets.instructions]
source = "AGENTS.md"
destination = "CLAUDE.md"
type = "symlink"

# Explicit nested targets
[agents.claude.targets.nested.agent-runtime]
source = "clients/agent-runtime/AGENTS.md"
destination = "clients/agent-runtime/AGENTS.md"
type = "symlink"

Downside: Requires manual configuration for each nested file.

Option C: Contextual Inheritance (Most Complex)

Implement a discovery mechanism that:

  1. Scans for all **/AGENTS.md files
  2. Creates a hierarchical symlink structure
  3. Respects inheritance rules per agent

Downside: Significant complexity; may conflict with agent-specific inheritance behavior.

Technical Considerations

1. Circular Reference Prevention

Ensure glob patterns don't accidentally include the root .agents/AGENTS.md creating loops.

2. Exclusion Patterns

Some directories should be excluded:

  • node_modules/
  • target/ (Rust)
  • build/ (Gradle)
  • .git/
  • dist/, coverage/

3. Incremental Sync

On subsequent runs, only sync changed/new/deleted files, not the entire glob result every time.

4. Conflict Resolution

If a nested AGENTS.md has the same content as the root, should it still create a symlink?
(Probably yes, for explicit submodule ownership.)

5. Performance

For large monorepos, glob patterns could match hundreds of files. Consider:

  • Caching the glob result
  • Parallel symlink creation
  • Incremental updates

Example Configuration (Option A)

# agentsync.toml

[agents.claude]
enabled = true

[agents.claude.targets.instructions]
source = "AGENTS.md"
destination = "CLAUDE.md"
type = "symlink"

# Nested discovery with exclusions
[agents.claude.targets.nested]
enabled = true
source_dir = "."
pattern = "**/AGENTS.md"
exclude = [
    ".agents/**",
    "node_modules/**",
    "**/target/**",
    "**/build/**",
    "**/dist/**",
    "**/.git/**"
]
destination_template = "{relative_path}/CLAUDE.md"
type = "symlink"

[agents.codex]
enabled = true

# Similar nested config for Codex
[agents.codex.targets.nested]
enabled = true
source_dir = "."
pattern = "**/AG...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes dallay/agentsync#233

<!-- START COPILOT CODING AGENT TIPS -->
---

📱 Kick off Copilot coding agent tasks wherever you are with [GitHub Mobile](https://gh.io/cca-mobile-docs), available on iOS and Android.

Adds a new `nested-glob` sync type that recursively discovers files
matching a glob pattern under a search root directory, then creates
a symlink for each discovered file at a path produced by expanding
a destination template.

Key changes:
- New `SyncType::NestedGlob` variant (TOML: `type = "nested-glob"`)
- New `exclude: Vec<String>` field on `TargetConfig` for exclusion patterns
- `process_nested_glob()` in linker.rs using walkdir for traversal
- `expand_destination_template()` with {relative_path}, {file_name},
  {stem}, {ext} placeholders; {relative_path} is "." for root-level files
- `matches_path_glob()` / `path_glob_match()` supporting ** multi-segment
  glob matching
- `clean()` extended to re-discover and remove nested-glob symlinks
- `all_gitignore_entries()` skips NestedGlob destinations (they're templates)
- Comprehensive unit tests (13 new tests)
- README documentation

Co-authored-by: yacosta738 <33158051+yacosta738@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dallay/agentsync/sessions/971330c2-c7c7-4439-9f72-cd0588402b5e
Copilot AI changed the title [WIP] Add support for nested AGENTS.md files feat: add nested-glob target type for monorepo/multi-module AGENTS.md discovery Mar 21, 2026
Copilot AI requested a review from yacosta738 March 21, 2026 23:12
@yacosta738
yacosta738 marked this pull request as ready for review March 21, 2026 23:25
…tion

- Use find() instead of any() for exclusion patterns to enable early-exit
  and show which pattern matched in verbose output
- Add comprehensive doc comments to process_nested_glob()
- Minor formatting improvements
- Set FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true in ci.yml and contributor-report.yml
- Update contributor-report.yml to use v1.1.0 of dallay/common-actions

Node.js 20 actions are deprecated and will be forced to Node.js 24 by
default starting June 2nd, 2026.
Upgrades reqwest from 0.13.1 to 0.13.2 which pulls in updated transitive
dependencies that fix the following RUSTSEC advisories:

- RUSTSEC-2026-0045: Timing Side-Channel in AES-CCM Tag Verification
- RUSTSEC-2026-0044: AWS-LC X.509 Name Constraints Bypass
- RUSTSEC-2026-0048: CRL Distribution Point Scope Check Logic Error
- RUSTSEC-2026-0047: PKCS7_verify Signature Validation Bypass
- RUSTSEC-2026-0046: PKCS7_verify Certificate Chain Validation Bypass
- RUSTSEC-2026-0049: CRLs not considered authoritative by Distribution Point
@yacosta738
yacosta738 merged commit 4ea1d59 into main Mar 22, 2026
21 of 22 checks passed
@yacosta738
yacosta738 deleted the copilot/support-nested-agents-md-files branch March 22, 2026 00:27
@dallay-bot dallay-bot Bot mentioned this pull request Mar 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants