# ADR-006: Inline Exclude in Josh-Proxy URL **Status:** Accepted **Date:** 2026-02 ## Context Some files in a monorepo subfolder should not appear in the subrepo (e.g., monorepo-specific CI configs, internal tooling, secrets templates). We need a mechanism to exclude these files from sync. ### Alternatives considered 1. **`.josh-sync-exclude` file committed to the repo**: A gitignore-style file listing patterns. Requires generating and committing a file. Changes to the exclude list create commits. The file itself would need to be excluded from the subrepo (circular dependency). 2. **Post-clone file deletion**: Clone through josh, then `rm -rf` excluded paths before pushing. Fragile — deletions create diff noise. Doesn't work for reverse sync (excluded files would appear as "deleted" in the subrepo). 3. **Josh `:exclude` filter inline in the URL**: Josh-proxy supports `:exclude[::pattern1,::pattern2]` appended to the filter path. The exclusion happens at the transport layer — git objects for excluded files are never transferred. Works identically for clone (forward) and push (reverse). 4. **Separate josh filter file**: Generate a josh filter expression and store it somewhere. Adds state management complexity. ## Decision Embed exclusion patterns inline in the josh-proxy URL using josh's native `:exclude` syntax. The `exclude` config field in `.josh-sync.yml` is transformed at config parse time into the josh filter string. ### Example Config: ```yaml exclude: - ".monorepo/" - "**/internal/" ``` Produces josh filter: ``` :/services/billing:exclude[::.monorepo/,::**/internal/] ``` ### Implementation The `parse_config()` function in `lib/config.sh` uses jq to conditionally append `:exclude[...]` to the josh filter when the `exclude` array is non-empty. The enriched filter is stored in `JOSH_SYNC_TARGETS` JSON and used everywhere via `$JOSH_FILTER`. ## Consequences **Positive:** - Zero committed files — exclusion is purely in the URL - Transport-layer filtering — excluded content never leaves the git server - Works identically for forward sync (clone), reverse sync (push), and reset - Tree comparison (`skip` detection) works correctly since excluded files aren't in the filtered view - Standard josh syntax — no custom invention **Negative:** - Josh's `:exclude` pattern syntax is limited (no negation, no regex — only glob-style patterns with `::` prefix) - Long exclude lists make the URL unwieldy (though this is cosmetic — git handles long URLs fine) - Changing the exclude list changes the josh filter, which changes all filtered SHAs (see ADR-007 for how this is handled) - Debugging requires understanding josh's filter composition syntax