Skip to content

Conversation

@edgarrmondragon
Copy link
Collaborator

@edgarrmondragon edgarrmondragon commented Dec 2, 2025

Links

Summary by Sourcery

Add optional AGENTS.md AI agent guidance files to tap, target, and mapper cookiecutter templates and ensure they are conditionally included based on a new template flag.

New Features:

  • Introduce AGENTS.md AI agent development guides for generated tap, target, and mapper projects.
  • Add a cookiecutter option to control inclusion of AGENTS.md in newly generated projects.

Tests:

  • Update end-to-end cookiecutter configuration fixtures to cover the new AGENTS.md inclusion option.

@edgarrmondragon edgarrmondragon self-assigned this Dec 2, 2025
@edgarrmondragon edgarrmondragon added Templates Tap, target and mapper templates LLM LLM and general AI use cases labels Dec 2, 2025
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 2, 2025

Reviewer's Guide

Adds AGENTS.md AI-agent development guides to tap, target, and mapper cookiecutter templates, and introduces a cookiecutter flag and post-gen hooks to optionally omit these files, updating test cookiecutter configs accordingly.

Sequence diagram for cookiecutter project generation with optional AGENTS_md

sequenceDiagram
    actor Developer
    participant Cookiecutter
    participant Post_gen_hook_mapper as Post_gen_hook_mapper
    participant Post_gen_hook_tap as Post_gen_hook_tap
    participant Post_gen_hook_target as Post_gen_hook_target
    participant FileSystem

    Developer->>Cookiecutter: Run mapper/tap/target template
    Cookiecutter->>FileSystem: Render project files
    Note over Cookiecutter,FileSystem: AGENTS_md is rendered by default

    alt Mapper template
        Cookiecutter->>Post_gen_hook_mapper: Execute post_gen_project
        Post_gen_hook_mapper->>Post_gen_hook_mapper: Check include_agents_md flag
        alt include_agents_md is false
            Post_gen_hook_mapper->>FileSystem: Delete AGENTS_md
        else include_agents_md is true
            Post_gen_hook_mapper->>FileSystem: Keep AGENTS_md
        end
    else Tap template
        Cookiecutter->>Post_gen_hook_tap: Execute post_gen_project
        Post_gen_hook_tap->>Post_gen_hook_tap: Check include_agents_md flag
        alt include_agents_md is false
            Post_gen_hook_tap->>FileSystem: Delete AGENTS_md
        else include_agents_md is true
            Post_gen_hook_tap->>FileSystem: Keep AGENTS_md
        end
    else Target template
        Cookiecutter->>Post_gen_hook_target: Execute post_gen_project
        Post_gen_hook_target->>Post_gen_hook_target: Check include_agents_md flag
        alt include_agents_md is false
            Post_gen_hook_target->>FileSystem: Delete AGENTS_md
        else include_agents_md is true
            Post_gen_hook_target->>FileSystem: Keep AGENTS_md
        end
    end

    Cookiecutter-->>Developer: Generated project (with or without AGENTS_md)
Loading

Flow diagram for post_gen_project handling of AGENTS_md

flowchart TD
    A_start["Start post_gen_project hook"] --> B_check_ide["Check cookiecutter_ide value"]
    B_check_ide -->|ide != VSCode| C_remove_vscode["Remove .vscode directory"]
    B_check_ide -->|ide == VSCode| D_skip_vscode["Skip .vscode removal"]

    C_remove_vscode --> E_check_agents["Check include_agents_md flag"]
    D_skip_vscode --> E_check_agents

    E_check_agents -->|include_agents_md is true| F_keep_agents["Keep AGENTS_md in project"]
    E_check_agents -->|include_agents_md is false| G_delete_agents["Delete AGENTS_md if present"]

    F_keep_agents --> H_end["End hook"]
    G_delete_agents --> H_end
Loading

File-Level Changes

Change Details Files
Add optional AGENTS.md AI-agent/developer guides to generated tap, target, and mapper projects, controlled by a new cookiecutter flag.
  • Introduce AGENTS.md template for mapper projects with detailed guidance on implementing and configuring Singer mappers using the Meltano Singer SDK.
  • Introduce AGENTS.md template for target projects with guidance tailored to different serialization methods (per record, per batch, SQL) and sink implementations.
  • Introduce AGENTS.md template for tap projects with guidance on streams, auth, pagination, state, and configuration patterns in Singer taps.
cookiecutter/mapper-template/{{cookiecutter.mapper_id}}/AGENTS.md
cookiecutter/target-template/{{cookiecutter.target_id}}/AGENTS.md
cookiecutter/tap-template/{{cookiecutter.tap_id}}/AGENTS.md
Wire a new include_agents_md cookiecutter option into mapper, tap, and target templates and their post-generation hooks to conditionally remove AGENTS.md.
  • Update mapper, tap, and target cookiecutter.json files to define the include_agents_md option used during template generation.
  • Extend mapper, tap, and target post_gen_project.py hooks to delete AGENTS.md when include_agents_md is false.
  • Ensure e2e cookiecutter config JSONs set appropriate defaults for include_agents_md so tests cover the new option.
cookiecutter/mapper-template/hooks/post_gen_project.py
cookiecutter/tap-template/hooks/post_gen_project.py
cookiecutter/target-template/hooks/post_gen_project.py
cookiecutter/mapper-template/cookiecutter.json
cookiecutter/tap-template/cookiecutter.json
cookiecutter/target-template/cookiecutter.json
e2e-tests/cookiecutters/mapper-base.json
e2e-tests/cookiecutters/tap-faker.json
e2e-tests/cookiecutters/tap-graphql-jwt.json
e2e-tests/cookiecutters/tap-no-license.json
e2e-tests/cookiecutters/tap-other-custom.json
e2e-tests/cookiecutters/tap-rest-api_key-github.json
e2e-tests/cookiecutters/tap-rest-basic_auth.json
e2e-tests/cookiecutters/tap-rest-bearer_token.json
e2e-tests/cookiecutters/tap-rest-custom.json
e2e-tests/cookiecutters/tap-rest-jwt.json
e2e-tests/cookiecutters/tap-rest-oauth2.json
e2e-tests/cookiecutters/tap-sql-custom.json
e2e-tests/cookiecutters/target-per_record.json
e2e-tests/cookiecutters/target-sql.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@edgarrmondragon edgarrmondragon force-pushed the feat/templates-agentsmd branch 2 times, most recently from a06bfe9 to 1b413d7 Compare December 2, 2025 21:19
@edgarrmondragon edgarrmondragon marked this pull request as ready for review December 2, 2025 22:58
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • In the post-gen hooks, consider using the existing BASE_PATH (or an equivalent project root Path) when unlinking AGENTS.md instead of relying on the current working directory, to keep path handling consistent with the rest of the hook logic and avoid CWD-related surprises.
  • The three AGENTS.md templates share a lot of overlapping guidance; consider extracting common sections into shared cookiecutter partials/includes so updates to the guidance only need to be made in one place.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the post-gen hooks, consider using the existing `BASE_PATH` (or an equivalent project root Path) when unlinking `AGENTS.md` instead of relying on the current working directory, to keep path handling consistent with the rest of the hook logic and avoid CWD-related surprises.
- The three AGENTS.md templates share a lot of overlapping guidance; consider extracting common sections into shared cookiecutter partials/includes so updates to the guidance only need to be made in one place.

## Individual Comments

### Comment 1
<location> `cookiecutter/mapper-template/hooks/post_gen_project.py:27-29` </location>
<code_context>
from pathlib import Path
import shutil


BASE_PATH = Path("{{cookiecutter.library_name}}")


if __name__ == "__main__":
    # Handle license selection
    license_choice = "{{ cookiecutter.license }}"
    if license_choice == "Apache-2.0":
        Path("LICENSE-Apache-2.0").rename("LICENSE")
        Path("LICENSE-MIT").unlink()
    elif license_choice == "MIT":
        Path("LICENSE-MIT").rename("LICENSE")
        Path("LICENSE-Apache-2.0").unlink()
    elif license_choice == "None":
        Path("LICENSE-Apache-2.0").unlink()
        Path("LICENSE-MIT").unlink()

    if "{{ cookiecutter.include_ci_files }}" != "GitHub":
        shutil.rmtree(Path(".github"))

    if "{{ cookiecutter.ide }}" != "VSCode":
        shutil.rmtree(".vscode", ignore_errors=True)

    if not {{ cookiecutter.include_agents_md }}:
        Path("AGENTS.md").unlink(missing_ok=True)

</code_context>

<issue_to_address>
**suggestion (code-quality):** We've found these issues:

- Remove redundant conditional ([`remove-redundant-if`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/remove-redundant-if/))
- Replace constant collection with boolean in boolean contexts ([`collection-to-bool`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/collection-to-bool/))

```suggestion

```
</issue_to_address>

### Comment 2
<location> `cookiecutter/tap-template/hooks/post_gen_project.py:57-59` </location>
<code_context>
from pathlib import Path
import shutil


PACKAGE_PATH = Path("{{cookiecutter.library_name}}")


if __name__ == "__main__":
    # Rename stream type client and delete others
    target = PACKAGE_PATH / "client.py"
    raw_client_py = PACKAGE_PATH / "{{cookiecutter.stream_type|lower}}-client.py"
    raw_client_py.rename(target)

    for client_py in PACKAGE_PATH.rglob("*-client.py"):
        client_py.unlink()

    # Select appropriate tap.py based on stream type
    tap_target = PACKAGE_PATH / "tap.py"
    if "{{ cookiecutter.stream_type }}" == "SQL":
        sql_tap_py = PACKAGE_PATH / "sql-tap.py"
        sql_tap_py.rename(tap_target)
    else:
        non_sql_tap_py = PACKAGE_PATH / "non-sql-tap.py"
        non_sql_tap_py.rename(tap_target)

    # Clean up remaining tap template files
    for tap_py in PACKAGE_PATH.rglob("*-tap.py"):
        tap_py.unlink()

    if "{{ cookiecutter.stream_type }}" != "REST":
        shutil.rmtree(PACKAGE_PATH.joinpath("schemas"), ignore_errors=True)

    if "{{ cookiecutter.auth_method }}" not in ("OAuth2", "JWT"):
        PACKAGE_PATH.joinpath("auth.py").unlink()

    if "{{ cookiecutter.stream_type }}" == "SQL":
        PACKAGE_PATH.joinpath("streams.py").unlink()

    # Handle license selection
    license_choice = "{{ cookiecutter.license }}"
    if license_choice == "Apache-2.0":
        Path("LICENSE-Apache-2.0").rename("LICENSE")
        Path("LICENSE-MIT").unlink()
    elif license_choice == "MIT":
        Path("LICENSE-MIT").rename("LICENSE")
        Path("LICENSE-Apache-2.0").unlink()
    elif license_choice == "None":
        Path("LICENSE-Apache-2.0").unlink()
        Path("LICENSE-MIT").unlink()

    if "{{ cookiecutter.include_ci_files }}" != "GitHub":
        shutil.rmtree(".github")

    if "{{ cookiecutter.ide }}" != "VSCode":
        shutil.rmtree(".vscode", ignore_errors=True)

    if not {{ cookiecutter.include_agents_md }}:
        Path("AGENTS.md").unlink(missing_ok=True)

</code_context>

<issue_to_address>
**suggestion (code-quality):** We've found these issues:

- Remove redundant conditional ([`remove-redundant-if`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/remove-redundant-if/))
- Replace constant collection with boolean in boolean contexts ([`collection-to-bool`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/collection-to-bool/))

```suggestion

```
</issue_to_address>

### Comment 3
<location> `cookiecutter/target-template/hooks/post_gen_project.py:52-54` </location>
<code_context>
from pathlib import Path
import shutil


BASE_PATH = Path("{{cookiecutter.library_name}}")


if __name__ == "__main__":
    # Handle license selection
    license_choice = "{{ cookiecutter.license }}"
    if license_choice == "Apache-2.0":
        Path("LICENSE-Apache-2.0").rename("LICENSE")
        Path("LICENSE-MIT").unlink()
    elif license_choice == "MIT":
        Path("LICENSE-MIT").rename("LICENSE")
        Path("LICENSE-Apache-2.0").unlink()
    elif license_choice == "None":
        Path("LICENSE-Apache-2.0").unlink()
        Path("LICENSE-MIT").unlink()

    if "{{ cookiecutter.include_ci_files }}" != "GitHub":
        shutil.rmtree(Path(".github"))

    if "{{ cookiecutter.ide }}" != "VSCode":
        shutil.rmtree(".vscode", ignore_errors=True)

    # Choose the appropriate sinks file based on serialization method
    serialization_method = "{{ cookiecutter.serialization_method }}"

    if serialization_method == "Per record":
        source_file = BASE_PATH / "sinks_record.py"
    elif serialization_method == "Per batch":
        source_file = BASE_PATH / "sinks_batch.py"
    elif serialization_method == "SQL":
        source_file = BASE_PATH / "sinks_sql.py"
    else:
        valid_methods = ["Per record", "Per batch", "SQL"]
        msg = (
            f"Unknown serialization method: {serialization_method}. "
            f"Valid methods are: {', '.join(valid_methods)}"
        )
        raise ValueError(msg)

    # Copy the appropriate sinks file to sinks.py
    target_file = BASE_PATH / "sinks.py"
    shutil.copy2(source_file, target_file)

    # Clean up the unused sink files
    for template in ["sinks_record.py", "sinks_batch.py", "sinks_sql.py"]:
        (BASE_PATH / template).unlink(missing_ok=True)

    if not {{ cookiecutter.include_agents_md }}:
        Path("AGENTS.md").unlink(missing_ok=True)

</code_context>

<issue_to_address>
**suggestion (code-quality):** We've found these issues:

- Remove redundant conditional ([`remove-redundant-if`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/remove-redundant-if/))
- Replace constant collection with boolean in boolean contexts ([`collection-to-bool`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/collection-to-bool/))

```suggestion

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@edgarrmondragon edgarrmondragon added this to the v0.54 milestone Dec 2, 2025
@edgarrmondragon edgarrmondragon changed the title feat(templates): Add AGENTS.md to templates feat(templates): Add AGENTS.md/CLAUDE.md to templates Dec 12, 2025
edgarrmondragon and others added 3 commits December 29, 2025 09:50
Signed-off-by: Edgar Ramírez Mondragón <edgarrm358@gmail.com>
Update cookiecutter post-generation hooks to create both AGENTS.md
(for broad AI tool ecosystem) and CLAUDE.md (for Claude Code) with
identical content. This ensures generated projects work with Claude
Code immediately while maintaining compatibility with 20+ other AI
coding assistants.

Uses AGENTS.md as the single source of truth, copying to CLAUDE.md
via shutil.copy2 to avoid symlink cross-platform issues on Windows.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

LLM LLM and general AI use cases Templates Tap, target and mapper templates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants