{"owner":"tailcallhq","repo":"forgecode","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md",".forge/skills/write-release-notes/SKILL.md","crates/forge_repo/src/skills/execute-plan/SKILL.md"],"skills":{"AGENTS.md":"# Agent Guidelines\n\nThis document contains guidelines and best practices for AI agents working with this codebase.\n\n## Error Management\n\n- Use `anyhow::Result` for error handling in services and repositories.\n- Create domain errors using `thiserror`.\n- Never implement `From` for converting domain errors, manually convert them\n\n## Writing Tests\n\n- All tests should be written in three discrete steps:\n\n  ```rust,ignore\n  use pretty_assertions::assert_eq; // Always use pretty assertions\n\n  fn test_foo() {\n      let setup = ...; // Instantiate a fixture or setup for the test\n      let actual = ...; // Execute the fixture to create an output\n      let expected = ...; // Define a hand written expected result\n      assert_eq!(actual, expected); // Assert that the actual result matches the expected result\n  }\n  ```\n\n- Use `pretty_assertions` for better error messages.\n\n- Use fixtures to create test data.\n\n- Use `assert_eq!` for equality checks.\n\n- Use `assert!(...)` for boolean checks.\n\n- Use unwraps in test functions and anyhow::Result in fixtures.\n\n- Keep the boilerplate to a minimum.\n\n- Use words like `fixture`, `actual` and `expected` in test functions.\n\n- Fixtures should be generic and reusable.\n\n- Test should always be written in the same file as the source code.\n\n- Use `new`, Default and derive_setters::Setters to create `actual`, `expected` and specially `fixtures`. For example:\n\n  **Good:**\n\n  ```rust,ignore\n  User::default().age(12).is_happy(true).name(\"John\")\n  User::new(\"Job\").age(12).is_happy()\n  User::test() // Special test constructor\n  ```\n\n  **Bad:**\n\n  ```rust,ignore\n  User {name: \"John\".to_string(), is_happy: true, age: 12}\n  User::with_name(\"Job\") // Bad name, should stick to User::new() or User::test()\n  ```\n\n- Use `unwrap()` unless the error information is useful. Use `expect` instead of `panic!` when error message is useful. For example:\n\n  **Good:**\n\n  ```rust,ignore\n  users.first().expect(\"List should not be empty\")\n  ```\n\n  **Bad:**\n\n  ```rust,ignore\n  if let Some(user) = users.first() {\n      // ...\n  } else {\n      panic!(\"List should not be empty\")\n  }\n  ```\n\n- Prefer using `assert_eq` on full objects instead of asserting each field:\n\n  **Good:**\n\n  ```rust,ignore\n  assert_eq!(actual, expected);\n  ```\n\n  **Bad:**\n\n  ```rust,ignore\n  assert_eq!(actual.a, expected.a);\n  assert_eq!(actual.b, expected.b);\n  ```\n\n## Verification\n\nAlways verify changes by running tests and linting the codebase\n\n1. Run crate specific tests to ensure they pass.\n\n   ```\n   cargo insta test --accept\n   ```\n\n2. **Build Guidelines**:\n   - **NEVER** run `cargo build --release` unless absolutely necessary (e.g., performance testing, creating binaries for distribution)\n   - For verification, use `cargo check` (fastest), `cargo insta test`, or `cargo build` (debug mode)\n   - Release builds take significantly longer and are rarely needed for development verification\n\n## Writing Domain Types\n\n- Use `derive_setters` to derive setters and use the `strip_option` and the `into` attributes on the struct types.\n\n## Documentation\n\n- **Always** write Rust docs (`///`) for all public methods, functions, structs, enums, and traits.\n- Document parameters with `# Arguments` and errors with `# Errors` sections when applicable.\n- **Do not include code examples** - docs are for LLMs, not humans. Focus on clear, concise functionality descriptions.\n\n## Refactoring\n\n- If asked to fix failing tests, always confirm whether to update the implementation or the tests.\n\n## Git Operations\n\n- Safely assume git is pre-installed\n- Safely assume github cli (gh) is pre-installed\n- Always use `Co-Authored-By: ForgeCode <noreply@forgecode.dev>` for git commits and Github comments\n\n## Service Implementation Guidelines\n\nServices should follow clean architecture principles and maintain clear separation of concerns:\n\n### Core Principles\n\n- **No service-to-service dependencies**: Services should never depend on other services directly\n- **Infrastructure dependency**: Services should depend only on infrastructure abstractions when needed\n- **Single type parameter**: Services should take at most one generic type parameter for infrastructure\n- **No trait objects**: Avoid `Box<dyn ...>` - use concrete types and generics instead\n- **Constructor pattern**: Implement `new()` without type bounds - apply bounds only on methods that need them\n- **Compose dependencies**: Use the `+` operator to combine multiple infrastructure traits into a single bound\n- **Arc<T> for infrastructure**: Store infrastructure as `Arc<T>` for cheap cloning and shared ownership\n- **Tuple struct pattern**: For simple services with single dependency, use tuple structs `struct Service<T>(Arc<T>)`\n\n### Examples\n\n#### Simple Service (No Infrastructure)\n\n```rust,ignore\npub struct UserValidationService;\n\nimpl UserValidationService {\n    pub fn new() -> Self { ... }\n\n    pub fn validate_email(&self, email: &str) -> Result<()> {\n        // Validation logic here\n        ...\n    }\n\n    pub fn validate_age(&self, age: u32) -> Result<()> {\n        // Age validation logic here\n        ...\n    }\n}\n```\n\n#### Service with Infrastructure Dependency\n\n```rust,ignore\n// Infrastructure trait (defined in infrastructure layer)\npub trait UserRepository {\n    fn find_by_email(&self, email: &str) -> Result<Option<User>>;\n    fn save(&self, user: &User) -> Result<()>;\n}\n\n// Service with single generic parameter using Arc\npub struct UserService<R> {\n    repository: Arc<R>,\n}\n\nimpl<R> UserService<R> {\n    // Constructor without type bounds, takes Arc<R>\n    pub fn new(repository: Arc<R>) -> Self { ... }\n}\n\nimpl<R: UserRepository> UserService<R> {\n    // Business logic methods have type bounds where needed\n    pub fn create_user(&self, email: &str, name: &str) -> Result<User> { ... }\n    pub fn find_user(&self, email: &str) -> Result<Option<User>> { ... }\n}\n```\n\n#### Tuple Struct Pattern for Simple Services\n\n```rust,ignore\n// Infrastructure traits\npub trait FileReader {\n    async fn read_file(&self, path: &Path) -> Result<String>;\n}\n\npub trait Environment {\n    fn max_file_size(&self) -> u64;\n}\n\n// Tuple struct for simple single dependency service\npub struct FileService<F>(Arc<F>);\n\nimpl<F> FileService<F> {\n    // Constructor without bounds\n    pub fn new(infra: Arc<F>) -> Self { ... }\n}\n\nimpl<F: FileReader + Environment> FileService<F> {\n    // Business logic methods with composed trait bounds\n    pub async fn read_with_validation(&self, path: &Path) -> Result<String> { ... }\n}\n```\n\n### Anti-patterns to Avoid\n\n```rust,ignore\n// BAD: Service depending on another service\npub struct BadUserService<R, E> {\n    repository: R,\n    email_service: E, // Don't do this!\n}\n\n// BAD: Using trait objects\npub struct BadUserService {\n    repository: Box<dyn UserRepository>, // Avoid Box<dyn>\n}\n\n// BAD: Multiple infrastructure dependencies with separate type parameters\npub struct BadUserService<R, C, L> {\n    repository: R,\n    cache: C,\n    logger: L, // Too many generic parameters - hard to use and test\n}\n\nimpl<R: UserRepository, C: Cache, L: Logger> BadUserService<R, C, L> {\n    // BAD: Constructor with type bounds makes it hard to use\n    pub fn new(repository: R, cache: C, logger: L) -> Self { ... }\n}\n\n// BAD: Usage becomes cumbersome\nlet service = BadUserService::<PostgresRepo, RedisCache, FileLogger>::new(...);\n```\n",".forge/skills/write-release-notes/SKILL.md":"---\nname: write-release-notes\ndescription: Generate engaging, high-energy release notes for a given version tag. Fetches the release from GitHub, retrieves every linked PR's title and description, then synthesizes all changes into a polished, user-facing release note with an enthusiastic tone. Use when the user asks to write, generate, or create release notes for a version (e.g. \"write release notes for v1.32.0\", \"generate release notes for the latest release\", \"create changelog for v2.0\").\n---\n\n# Write Release Notes\n\nGenerate clear, informative, and enthusiastic release notes by pulling live data from GitHub and synthesizing every PR into a cohesive narrative.\n\n## Workflow\n\n### 1. Fetch Release Data\n\nRun the bundled script to pull the release metadata and all linked PR details in one shot:\n\n```bash\nbash .forge/skills/write-release-notes/scripts/fetch-release-data.sh <version> [owner/repo]\n```\n\n- `<version>`: The release tag (e.g. `v1.32.0`)\n- `[owner/repo]`: Optional. Defaults to the current repo detected via `gh repo view`.\n\nThe script outputs two sections:\n- `### RELEASE METADATA ###` — tag name, publish date, release name, raw body\n- `### PR DETAILS ###` — one JSON object per PR with: `number`, `title`, `body`, `labels`, `author`, `mergedAt`, `url`\n\n### 2. Categorize Changes\n\nGroup PRs by their conventional commit prefix or label:\n\n| Category | Prefixes / Labels |\n|---|---|\n| Features | `feat`, `type: feature` |\n| Bug Fixes | `fix`, `type: fix` |\n| Performance | `perf` |\n| Refactors | `refactor` |\n| Maintenance | `chore`, `docs`, `ci`, `build`, `deps` |\n\nDependency bumps (e.g. Dependabot PRs) go into Maintenance. Skip PRs with `error: \"not found\"`.\n\n### 3. Write the Release Notes\n\nProduce a Markdown document with the following structure. Keep the tone **informative and enthusiastic** — explain what changed and why it matters, without resorting to marketing fluff.\n\n```markdown\n# [Product Name] [Version] — [Descriptive Tagline]\n\n> One-sentence summary of what this release focuses on.\n\n## What's New\n\n[2-4 sentence narrative covering the biggest features and fixes. \nDescribe what changed and what users can now do. Use active voice. Be factual but upbeat.]\n\n## Highlights\n\n### [Feature/Fix Category]\n**[PR Title rephrased as a clear description of the change]**\n[1-2 sentences expanding on the PR description. Explain what changed and what users can now do differently. \nIf the PR body has useful context, distill it. If empty, infer from the title.]\n\n[Repeat for each significant PR — skip pure chores/dep bumps unless noteworthy]\n\n## Bug Fixes & Reliability\n\n[Bullet list of fixes, each with a brief impact statement]\n\n## Under the Hood\n\n[Brief paragraph or bullet list covering refactors, maintenance, and dep updates — \nkeep it light, acknowledge the work without boring the reader]\n\n## Contributors\n\nA huge thank you to everyone who made this release happen: [list @handles — exclude bots like @dependabot]\n\n---\n**Full changelog**: [GitHub Release link]\n```\n\n### 4. Tone & Style Guidelines\n\n- **Lead with what changed**: \"You can now...\" or \"Forge now...\" beats \"We added...\"\n- **Be specific**: Name the feature and describe what it does, not just the category\n- **Be informative, not marketty**: Avoid vague adjectives like \"seamless\", \"smarter\", \"blazing\", \"powerful\", \"rock-solid\". Instead, state the concrete fact (e.g. \"editor no longer spawns a git process on every keystroke\" beats \"blazing-fast editor\")\n- **Enthusiasm through substance**: Let the actual improvement speak for itself. Use active, direct language.\n- **Short paragraphs**: Max 3 sentences per block\n- **Skip internal jargon**: Translate crate names and internal concepts into plain language\n- **Celebrate contributors**: Name them by handle\n- **Tagline formula**: `[Version] — [Factual Theme Description]` (e.g. \"v1.32.0 — Terminal Context, File Drop Support, Windows Performance\")\n- **No implementation details**: Do not mention internal module names, struct names, function names, crate names, or how something was implemented. Focus purely on what the user experiences or gains.\n- **No PR/issue references**: Do not include PR numbers, issue numbers, or links to GitHub PRs/issues in the release notes. Focus on the changes themselves, not their tracking identifiers.\n\n### 5. Contributors Filter\n\nOnly include **external contributors** in the Contributors section — exclude the core team:\n- `@tusharmath`\n- `@amitksingh1490`\n- `@laststylebender14`\n- Bots (e.g. `@dependabot`)\n\nIf no external contributors exist, omit the Contributors section entirely.\n\n### 6. Validate Length\n\nAfter writing the release notes, run the bundled validation script to confirm the output is under 2000 characters:\n\n```bash\necho \"<release notes>\" | bash .forge/skills/write-release-notes/scripts/validate-release-notes.sh\n```\n\nIf it prints `FAIL`, trim the draft and re-run until it prints `PASS`:\n- Remove the Under the Hood section first\n- Consolidate Bug Fixes into a shorter bullet list\n- Shorten individual PR descriptions to one tight sentence\n- Remove the least impactful Highlights entries\n\n### 7. Output\n\nPrint the final release notes directly in the chat. Do not write to a file unless the user explicitly asks.\n\n## Notes\n\n- The script handles ANSI color codes injected by `gh` CLI automatically.\n- PRs not found (closed without merge, private, etc.) are silently skipped.\n- If the release has no linked PRs in its body, fall back to listing commits between tags:\n  ```bash\n  gh api repos/<owner>/<repo>/compare/<prev_tag>...<version> --jq '.commits[].commit.message'\n  ```\n","crates/forge_repo/src/skills/execute-plan/SKILL.md":"---\nname: execute-plan\ndescription: Execute structured task plans with status tracking. Use when the user provides a plan file path in the format `plans/{current-date}-{task-name}-{version}.md` or explicitly asks you to execute a plan file.\n---\n\n# Execute Plan\n\nExecute structured task plans with automatic status tracking and progress updates.\n\n## Commitment to Completion\n\nWhen a plan is provided, **all tasks in the plan must be completed**. Before starting execution, recite:\n\n> \"I will execute this plan to completion. All the 20 tasks will be addressed and marked as DONE.\"\n\n## Execution Steps\n\n**STEP 1**: Recite the commitment to complete all tasks in the plan.\n\n**STEP 2**: Read the entire plan file to identify pending tasks based on `task_status`.\n\n**STEP 3**: Announce the next pending task and update its status to `IN_PROGRESS` in the plan file.\n\n**STEP 4**: Execute all actions required to complete the task and mark the task status to `DONE` in the plan file.\n\n**STEP 5**: Repeat from Step 3 until all tasks are marked as `DONE`.\n\n**STEP 6**: Re-read the plan file to verify all tasks are completed before announcing completion.\n\n## Task Status Format\n\nUse these status indicators in the plan file:\n\n```\n[ ]: PENDING\n[~]: IN_PROGRESS\n[x]: DONE\n[!]: FAILED\n```\n\n## Example Usage\n\n1. User provides: \"Execute plan at plans/2025-11-23-refactor-auth-v1.md\"\n2. Recite commitment: \"I will execute this plan to completion...\"\n3. Read the plan file\n4. Find first `[ ]` (PENDING) task\n5. Update to `[~]` (IN_PROGRESS)\n6. Execute the task\n7. Update to `[x]` (DONE)\n8. Move to next PENDING task\n9. Repeat until all tasks appear DONE\n10. Re-read plan file to verify completion\n11. Announce completion\n"},"files":{"AGENTS.md":"# Agent Guidelines\n\nThis document contains guidelines and best practices for AI agents working with this codebase.\n\n## Error Management\n\n- Use `anyhow::Result` for error handling in services and repositories.\n- Create domain errors using `thiserror`.\n- Never implement `From` for converting domain errors, manually convert them\n\n## Writing Tests\n\n- All tests should be written in three discrete steps:\n\n  ```rust,ignore\n  use pretty_assertions::assert_eq; // Always use pretty assertions\n\n  fn test_foo() {\n      let setup = ...; // Instantiate a fixture or setup for the test\n      let actual = ...; // Execute the fixture to create an output\n      let expected = ...; // Define a hand written expected result\n      assert_eq!(actual, expected); // Assert that the actual result matches the expected result\n  }\n  ```\n\n- Use `pretty_assertions` for better error messages.\n\n- Use fixtures to create test data.\n\n- Use `assert_eq!` for equality checks.\n\n- Use `assert!(...)` for boolean checks.\n\n- Use unwraps in test functions and anyhow::Result in fixtures.\n\n- Keep the boilerplate to a minimum.\n\n- Use words like `fixture`, `actual` and `expected` in test functions.\n\n- Fixtures should be generic and reusable.\n\n- Test should always be written in the same file as the source code.\n\n- Use `new`, Default and derive_setters::Setters to create `actual`, `expected` and specially `fixtures`. For example:\n\n  **Good:**\n\n  ```rust,ignore\n  User::default().age(12).is_happy(true).name(\"John\")\n  User::new(\"Job\").age(12).is_happy()\n  User::test() // Special test constructor\n  ```\n\n  **Bad:**\n\n  ```rust,ignore\n  User {name: \"John\".to_string(), is_happy: true, age: 12}\n  User::with_name(\"Job\") // Bad name, should stick to User::new() or User::test()\n  ```\n\n- Use `unwrap()` unless the error information is useful. Use `expect` instead of `panic!` when error message is useful. For example:\n\n  **Good:**\n\n  ```rust,ignore\n  users.first().expect(\"List should not be empty\")\n  ```\n\n  **Bad:**\n\n  ```rust,ignore\n  if let Some(user) = users.first() {\n      // ...\n  } else {\n      panic!(\"List should not be empty\")\n  }\n  ```\n\n- Prefer using `assert_eq` on full objects instead of asserting each field:\n\n  **Good:**\n\n  ```rust,ignore\n  assert_eq!(actual, expected);\n  ```\n\n  **Bad:**\n\n  ```rust,ignore\n  assert_eq!(actual.a, expected.a);\n  assert_eq!(actual.b, expected.b);\n  ```\n\n## Verification\n\nAlways verify changes by running tests and linting the codebase\n\n1. Run crate specific tests to ensure they pass.\n\n   ```\n   cargo insta test --accept\n   ```\n\n2. **Build Guidelines**:\n   - **NEVER** run `cargo build --release` unless absolutely necessary (e.g., performance testing, creating binaries for distribution)\n   - For verification, use `cargo check` (fastest), `cargo insta test`, or `cargo build` (debug mode)\n   - Release builds take significantly longer and are rarely needed for development verification\n\n## Writing Domain Types\n\n- Use `derive_setters` to derive setters and use the `strip_option` and the `into` attributes on the struct types.\n\n## Documentation\n\n- **Always** write Rust docs (`///`) for all public methods, functions, structs, enums, and traits.\n- Document parameters with `# Arguments` and errors with `# Errors` sections when applicable.\n- **Do not include code examples** - docs are for LLMs, not humans. Focus on clear, concise functionality descriptions.\n\n## Refactoring\n\n- If asked to fix failing tests, always confirm whether to update the implementation or the tests.\n\n## Git Operations\n\n- Safely assume git is pre-installed\n- Safely assume github cli (gh) is pre-installed\n- Always use `Co-Authored-By: ForgeCode <noreply@forgecode.dev>` for git commits and Github comments\n\n## Service Implementation Guidelines\n\nServices should follow clean architecture principles and maintain clear separation of concerns:\n\n### Core Principles\n\n- **No service-to-service dependencies**: Services should never depend on other services directly\n- **Infrastructure dependency**: Services should depend only on infrastructure abstractions when needed\n- **Single type parameter**: Services should take at most one generic type parameter for infrastructure\n- **No trait objects**: Avoid `Box<dyn ...>` - use concrete types and generics instead\n- **Constructor pattern**: Implement `new()` without type bounds - apply bounds only on methods that need them\n- **Compose dependencies**: Use the `+` operator to combine multiple infrastructure traits into a single bound\n- **Arc<T> for infrastructure**: Store infrastructure as `Arc<T>` for cheap cloning and shared ownership\n- **Tuple struct pattern**: For simple services with single dependency, use tuple structs `struct Service<T>(Arc<T>)`\n\n### Examples\n\n#### Simple Service (No Infrastructure)\n\n```rust,ignore\npub struct UserValidationService;\n\nimpl UserValidationService {\n    pub fn new() -> Self { ... }\n\n    pub fn validate_email(&self, email: &str) -> Result<()> {\n        // Validation logic here\n        ...\n    }\n\n    pub fn validate_age(&self, age: u32) -> Result<()> {\n        // Age validation logic here\n        ...\n    }\n}\n```\n\n#### Service with Infrastructure Dependency\n\n```rust,ignore\n// Infrastructure trait (defined in infrastructure layer)\npub trait UserRepository {\n    fn find_by_email(&self, email: &str) -> Result<Option<User>>;\n    fn save(&self, user: &User) -> Result<()>;\n}\n\n// Service with single generic parameter using Arc\npub struct UserService<R> {\n    repository: Arc<R>,\n}\n\nimpl<R> UserService<R> {\n    // Constructor without type bounds, takes Arc<R>\n    pub fn new(repository: Arc<R>) -> Self { ... }\n}\n\nimpl<R: UserRepository> UserService<R> {\n    // Business logic methods have type bounds where needed\n    pub fn create_user(&self, email: &str, name: &str) -> Result<User> { ... }\n    pub fn find_user(&self, email: &str) -> Result<Option<User>> { ... }\n}\n```\n\n#### Tuple Struct Pattern for Simple Services\n\n```rust,ignore\n// Infrastructure traits\npub trait FileReader {\n    async fn read_file(&self, path: &Path) -> Result<String>;\n}\n\npub trait Environment {\n    fn max_file_size(&self) -> u64;\n}\n\n// Tuple struct for simple single dependency service\npub struct FileService<F>(Arc<F>);\n\nimpl<F> FileService<F> {\n    // Constructor without bounds\n    pub fn new(infra: Arc<F>) -> Self { ... }\n}\n\nimpl<F: FileReader + Environment> FileService<F> {\n    // Business logic methods with composed trait bounds\n    pub async fn read_with_validation(&self, path: &Path) -> Result<String> { ... }\n}\n```\n\n### Anti-patterns to Avoid\n\n```rust,ignore\n// BAD: Service depending on another service\npub struct BadUserService<R, E> {\n    repository: R,\n    email_service: E, // Don't do this!\n}\n\n// BAD: Using trait objects\npub struct BadUserService {\n    repository: Box<dyn UserRepository>, // Avoid Box<dyn>\n}\n\n// BAD: Multiple infrastructure dependencies with separate type parameters\npub struct BadUserService<R, C, L> {\n    repository: R,\n    cache: C,\n    logger: L, // Too many generic parameters - hard to use and test\n}\n\nimpl<R: UserRepository, C: Cache, L: Logger> BadUserService<R, C, L> {\n    // BAD: Constructor with type bounds makes it hard to use\n    pub fn new(repository: R, cache: C, logger: L) -> Self { ... }\n}\n\n// BAD: Usage becomes cumbersome\nlet service = BadUserService::<PostgresRepo, RedisCache, FileLogger>::new(...);\n```\n",".forge/skills/write-release-notes/SKILL.md":"---\nname: write-release-notes\ndescription: Generate engaging, high-energy release notes for a given version tag. Fetches the release from GitHub, retrieves every linked PR's title and description, then synthesizes all changes into a polished, user-facing release note with an enthusiastic tone. Use when the user asks to write, generate, or create release notes for a version (e.g. \"write release notes for v1.32.0\", \"generate release notes for the latest release\", \"create changelog for v2.0\").\n---\n\n# Write Release Notes\n\nGenerate clear, informative, and enthusiastic release notes by pulling live data from GitHub and synthesizing every PR into a cohesive narrative.\n\n## Workflow\n\n### 1. Fetch Release Data\n\nRun the bundled script to pull the release metadata and all linked PR details in one shot:\n\n```bash\nbash .forge/skills/write-release-notes/scripts/fetch-release-data.sh <version> [owner/repo]\n```\n\n- `<version>`: The release tag (e.g. `v1.32.0`)\n- `[owner/repo]`: Optional. Defaults to the current repo detected via `gh repo view`.\n\nThe script outputs two sections:\n- `### RELEASE METADATA ###` — tag name, publish date, release name, raw body\n- `### PR DETAILS ###` — one JSON object per PR with: `number`, `title`, `body`, `labels`, `author`, `mergedAt`, `url`\n\n### 2. Categorize Changes\n\nGroup PRs by their conventional commit prefix or label:\n\n| Category | Prefixes / Labels |\n|---|---|\n| Features | `feat`, `type: feature` |\n| Bug Fixes | `fix`, `type: fix` |\n| Performance | `perf` |\n| Refactors | `refactor` |\n| Maintenance | `chore`, `docs`, `ci`, `build`, `deps` |\n\nDependency bumps (e.g. Dependabot PRs) go into Maintenance. Skip PRs with `error: \"not found\"`.\n\n### 3. Write the Release Notes\n\nProduce a Markdown document with the following structure. Keep the tone **informative and enthusiastic** — explain what changed and why it matters, without resorting to marketing fluff.\n\n```markdown\n# [Product Name] [Version] — [Descriptive Tagline]\n\n> One-sentence summary of what this release focuses on.\n\n## What's New\n\n[2-4 sentence narrative covering the biggest features and fixes. \nDescribe what changed and what users can now do. Use active voice. Be factual but upbeat.]\n\n## Highlights\n\n### [Feature/Fix Category]\n**[PR Title rephrased as a clear description of the change]**\n[1-2 sentences expanding on the PR description. Explain what changed and what users can now do differently. \nIf the PR body has useful context, distill it. If empty, infer from the title.]\n\n[Repeat for each significant PR — skip pure chores/dep bumps unless noteworthy]\n\n## Bug Fixes & Reliability\n\n[Bullet list of fixes, each with a brief impact statement]\n\n## Under the Hood\n\n[Brief paragraph or bullet list covering refactors, maintenance, and dep updates — \nkeep it light, acknowledge the work without boring the reader]\n\n## Contributors\n\nA huge thank you to everyone who made this release happen: [list @handles — exclude bots like @dependabot]\n\n---\n**Full changelog**: [GitHub Release link]\n```\n\n### 4. Tone & Style Guidelines\n\n- **Lead with what changed**: \"You can now...\" or \"Forge now...\" beats \"We added...\"\n- **Be specific**: Name the feature and describe what it does, not just the category\n- **Be informative, not marketty**: Avoid vague adjectives like \"seamless\", \"smarter\", \"blazing\", \"powerful\", \"rock-solid\". Instead, state the concrete fact (e.g. \"editor no longer spawns a git process on every keystroke\" beats \"blazing-fast editor\")\n- **Enthusiasm through substance**: Let the actual improvement speak for itself. Use active, direct language.\n- **Short paragraphs**: Max 3 sentences per block\n- **Skip internal jargon**: Translate crate names and internal concepts into plain language\n- **Celebrate contributors**: Name them by handle\n- **Tagline formula**: `[Version] — [Factual Theme Description]` (e.g. \"v1.32.0 — Terminal Context, File Drop Support, Windows Performance\")\n- **No implementation details**: Do not mention internal module names, struct names, function names, crate names, or how something was implemented. Focus purely on what the user experiences or gains.\n- **No PR/issue references**: Do not include PR numbers, issue numbers, or links to GitHub PRs/issues in the release notes. Focus on the changes themselves, not their tracking identifiers.\n\n### 5. Contributors Filter\n\nOnly include **external contributors** in the Contributors section — exclude the core team:\n- `@tusharmath`\n- `@amitksingh1490`\n- `@laststylebender14`\n- Bots (e.g. `@dependabot`)\n\nIf no external contributors exist, omit the Contributors section entirely.\n\n### 6. Validate Length\n\nAfter writing the release notes, run the bundled validation script to confirm the output is under 2000 characters:\n\n```bash\necho \"<release notes>\" | bash .forge/skills/write-release-notes/scripts/validate-release-notes.sh\n```\n\nIf it prints `FAIL`, trim the draft and re-run until it prints `PASS`:\n- Remove the Under the Hood section first\n- Consolidate Bug Fixes into a shorter bullet list\n- Shorten individual PR descriptions to one tight sentence\n- Remove the least impactful Highlights entries\n\n### 7. Output\n\nPrint the final release notes directly in the chat. Do not write to a file unless the user explicitly asks.\n\n## Notes\n\n- The script handles ANSI color codes injected by `gh` CLI automatically.\n- PRs not found (closed without merge, private, etc.) are silently skipped.\n- If the release has no linked PRs in its body, fall back to listing commits between tags:\n  ```bash\n  gh api repos/<owner>/<repo>/compare/<prev_tag>...<version> --jq '.commits[].commit.message'\n  ```\n","crates/forge_repo/src/skills/execute-plan/SKILL.md":"---\nname: execute-plan\ndescription: Execute structured task plans with status tracking. Use when the user provides a plan file path in the format `plans/{current-date}-{task-name}-{version}.md` or explicitly asks you to execute a plan file.\n---\n\n# Execute Plan\n\nExecute structured task plans with automatic status tracking and progress updates.\n\n## Commitment to Completion\n\nWhen a plan is provided, **all tasks in the plan must be completed**. Before starting execution, recite:\n\n> \"I will execute this plan to completion. All the 20 tasks will be addressed and marked as DONE.\"\n\n## Execution Steps\n\n**STEP 1**: Recite the commitment to complete all tasks in the plan.\n\n**STEP 2**: Read the entire plan file to identify pending tasks based on `task_status`.\n\n**STEP 3**: Announce the next pending task and update its status to `IN_PROGRESS` in the plan file.\n\n**STEP 4**: Execute all actions required to complete the task and mark the task status to `DONE` in the plan file.\n\n**STEP 5**: Repeat from Step 3 until all tasks are marked as `DONE`.\n\n**STEP 6**: Re-read the plan file to verify all tasks are completed before announcing completion.\n\n## Task Status Format\n\nUse these status indicators in the plan file:\n\n```\n[ ]: PENDING\n[~]: IN_PROGRESS\n[x]: DONE\n[!]: FAILED\n```\n\n## Example Usage\n\n1. User provides: \"Execute plan at plans/2025-11-23-refactor-auth-v1.md\"\n2. Recite commitment: \"I will execute this plan to completion...\"\n3. Read the plan file\n4. Find first `[ ]` (PENDING) task\n5. Update to `[~]` (IN_PROGRESS)\n6. Execute the task\n7. Update to `[x]` (DONE)\n8. Move to next PENDING task\n9. Repeat until all tasks appear DONE\n10. Re-read plan file to verify completion\n11. Announce completion\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# Agent Guidelines\n\nThis document contains guidelines and best practices for AI agents working with this codebase.\n\n## Error Management\n\n- Use `anyhow::Result` for error handling in services and repositories.\n- Create domain errors using `thiserror`.\n- Never implement `From` for converting domain errors, manually convert them\n\n## Writing Tests\n\n- All tests should be written in three discrete steps:\n\n  ```rust,ignore\n  use pretty_assertions::assert_eq; // Always use pretty assertions\n\n  fn test_foo() {\n      let setup = ...; // Instantiate a fixture or setup for the test\n      let actual = ...; // Execute the fixture to create an output\n      let expected = ...; // Define a hand written expected result\n      assert_eq!(actual, expected); // Assert that the actual result matches the expected result\n  }\n  ```\n\n- Use `pretty_assertions` for better error messages.\n\n- Use fixtures to create test data.\n\n- Use `assert_eq!` for equality checks.\n\n- Use `assert!(...)` for boolean checks.\n\n- Use unwraps in test functions and anyhow::Result in fixtures.\n\n- Keep the boilerplate to a minimum.\n\n- Use words like `fixture`, `actual` and `expected` in test functions.\n\n- Fixtures should be generic and reusable.\n\n- Test should always be written in the same file as the source code.\n\n- Use `new`, Default and derive_setters::Setters to create `actual`, `expected` and specially `fixtures`. For example:\n\n  **Good:**\n\n  ```rust,ignore\n  User::default().age(12).is_happy(true).name(\"John\")\n  User::new(\"Job\").age(12).is_happy()\n  User::test() // Special test constructor\n  ```\n\n  **Bad:**\n\n  ```rust,ignore\n  User {name: \"John\".to_string(), is_happy: true, age: 12}\n  User::with_name(\"Job\") // Bad name, should stick to User::new() or User::test()\n  ```\n\n- Use `unwrap()` unless the error information is useful. Use `expect` instead of `panic!` when error message is useful. For example:\n\n  **Good:**\n\n  ```rust,ignore\n  users.first().expect(\"List should not be empty\")\n  ```\n\n  **Bad:**\n\n  ```rust,ignore\n  if let Some(user) = users.first() {\n      // ...\n  } else {\n      panic!(\"List should not be empty\")\n  }\n  ```\n\n- Prefer using `assert_eq` on full objects instead of asserting each field:\n\n  **Good:**\n\n  ```rust,ignore\n  assert_eq!(actual, expected);\n  ```\n\n  **Bad:**\n\n  ```rust,ignore\n  assert_eq!(actual.a, expected.a);\n  assert_eq!(actual.b, expected.b);\n  ```\n\n## Verification\n\nAlways verify changes by running tests and linting the codebase\n\n1. Run crate specific tests to ensure they pass.\n\n   ```\n   cargo insta test --accept\n   ```\n\n2. **Build Guidelines**:\n   - **NEVER** run `cargo build --release` unless absolutely necessary (e.g., performance testing, creating binaries for distribution)\n   - For verification, use `cargo check` (fastest), `cargo insta test`, or `cargo build` (debug mode)\n   - Release builds take significantly longer and are rarely needed for development verification\n\n## Writing Domain Types\n\n- Use `derive_setters` to derive setters and use the `strip_option` and the `into` attributes on the struct types.\n\n## Documentation\n\n- **Always** write Rust docs (`///`) for all public methods, functions, structs, enums, and traits.\n- Document parameters with `# Arguments` and errors with `# Errors` sections when applicable.\n- **Do not include code examples** - docs are for LLMs, not humans. Focus on clear, concise functionality descriptions.\n\n## Refactoring\n\n- If asked to fix failing tests, always confirm whether to update the implementation or the tests.\n\n## Git Operations\n\n- Safely assume git is pre-installed\n- Safely assume github cli (gh) is pre-installed\n- Always use `Co-Authored-By: ForgeCode <noreply@forgecode.dev>` for git commits and Github comments\n\n## Service Implementation Guidelines\n\nServices should follow clean architecture principles and maintain clear separation of concerns:\n\n### Core Principles\n\n- **No service-to-service dependencies**: Services should never depend on other services directly\n- **Infrastructure dependency**: Services should depend only on infrastructure abstractions when needed\n- **Single type parameter**: Services should take at most one generic type parameter for infrastructure\n- **No trait objects**: Avoid `Box<dyn ...>` - use concrete types and generics instead\n- **Constructor pattern**: Implement `new()` without type bounds - apply bounds only on methods that need them\n- **Compose dependencies**: Use the `+` operator to combine multiple infrastructure traits into a single bound\n- **Arc<T> for infrastructure**: Store infrastructure as `Arc<T>` for cheap cloning and shared ownership\n- **Tuple struct pattern**: For simple services with single dependency, use tuple structs `struct Service<T>(Arc<T>)`\n\n### Examples\n\n#### Simple Service (No Infrastructure)\n\n```rust,ignore\npub struct UserValidationService;\n\nimpl UserValidationService {\n    pub fn new() -> Self { ... }\n\n    pub fn validate_email(&self, email: &str) -> Result<()> {\n        // Validation logic here\n        ...\n    }\n\n    pub fn validate_age(&self, age: u32) -> Result<()> {\n        // Age validation logic here\n        ...\n    }\n}\n```\n\n#### Service with Infrastructure Dependency\n\n```rust,ignore\n// Infrastructure trait (defined in infrastructure layer)\npub trait UserRepository {\n    fn find_by_email(&self, email: &str) -> Result<Option<User>>;\n    fn save(&self, user: &User) -> Result<()>;\n}\n\n// Service with single generic parameter using Arc\npub struct UserService<R> {\n    repository: Arc<R>,\n}\n\nimpl<R> UserService<R> {\n    // Constructor without type bounds, takes Arc<R>\n    pub fn new(repository: Arc<R>) -> Self { ... }\n}\n\nimpl<R: UserRepository> UserService<R> {\n    // Business logic methods have type bounds where needed\n    pub fn create_user(&self, email: &str, name: &str) -> Result<User> { ... }\n    pub fn find_user(&self, email: &str) -> Result<Option<User>> { ... }\n}\n```\n\n#### Tuple Struct Pattern for Simple Services\n\n```rust,ignore\n// Infrastructure traits\npub trait FileReader {\n    async fn read_file(&self, path: &Path) -> Result<String>;\n}\n\npub trait Environment {\n    fn max_file_size(&self) -> u64;\n}\n\n// Tuple struct for simple single dependency service\npub struct FileService<F>(Arc<F>);\n\nimpl<F> FileService<F> {\n    // Constructor without bounds\n    pub fn new(infra: Arc<F>) -> Self { ... }\n}\n\nimpl<F: FileReader + Environment> FileService<F> {\n    // Business logic methods with composed trait bounds\n    pub async fn read_with_validation(&self, path: &Path) -> Result<String> { ... }\n}\n```\n\n### Anti-patterns to Avoid\n\n```rust,ignore\n// BAD: Service depending on another service\npub struct BadUserService<R, E> {\n    repository: R,\n    email_service: E, // Don't do this!\n}\n\n// BAD: Using trait objects\npub struct BadUserService {\n    repository: Box<dyn UserRepository>, // Avoid Box<dyn>\n}\n\n// BAD: Multiple infrastructure dependencies with separate type parameters\npub struct BadUserService<R, C, L> {\n    repository: R,\n    cache: C,\n    logger: L, // Too many generic parameters - hard to use and test\n}\n\nimpl<R: UserRepository, C: Cache, L: Logger> BadUserService<R, C, L> {\n    // BAD: Constructor with type bounds makes it hard to use\n    pub fn new(repository: R, cache: C, logger: L) -> Self { ... }\n}\n\n// BAD: Usage becomes cumbersome\nlet service = BadUserService::<PostgresRepo, RedisCache, FileLogger>::new(...);\n```\n","category":"root","tokens":1833},{"name":"SKILL.md","path":".forge/skills/write-release-notes/SKILL.md","title":"write-release-notes Skill","content":"---\nname: write-release-notes\ndescription: Generate engaging, high-energy release notes for a given version tag. Fetches the release from GitHub, retrieves every linked PR's title and description, then synthesizes all changes into a polished, user-facing release note with an enthusiastic tone. Use when the user asks to write, generate, or create release notes for a version (e.g. \"write release notes for v1.32.0\", \"generate release notes for the latest release\", \"create changelog for v2.0\").\n---\n\n# Write Release Notes\n\nGenerate clear, informative, and enthusiastic release notes by pulling live data from GitHub and synthesizing every PR into a cohesive narrative.\n\n## Workflow\n\n### 1. Fetch Release Data\n\nRun the bundled script to pull the release metadata and all linked PR details in one shot:\n\n```bash\nbash .forge/skills/write-release-notes/scripts/fetch-release-data.sh <version> [owner/repo]\n```\n\n- `<version>`: The release tag (e.g. `v1.32.0`)\n- `[owner/repo]`: Optional. Defaults to the current repo detected via `gh repo view`.\n\nThe script outputs two sections:\n- `### RELEASE METADATA ###` — tag name, publish date, release name, raw body\n- `### PR DETAILS ###` — one JSON object per PR with: `number`, `title`, `body`, `labels`, `author`, `mergedAt`, `url`\n\n### 2. Categorize Changes\n\nGroup PRs by their conventional commit prefix or label:\n\n| Category | Prefixes / Labels |\n|---|---|\n| Features | `feat`, `type: feature` |\n| Bug Fixes | `fix`, `type: fix` |\n| Performance | `perf` |\n| Refactors | `refactor` |\n| Maintenance | `chore`, `docs`, `ci`, `build`, `deps` |\n\nDependency bumps (e.g. Dependabot PRs) go into Maintenance. Skip PRs with `error: \"not found\"`.\n\n### 3. Write the Release Notes\n\nProduce a Markdown document with the following structure. Keep the tone **informative and enthusiastic** — explain what changed and why it matters, without resorting to marketing fluff.\n\n```markdown\n# [Product Name] [Version] — [Descriptive Tagline]\n\n> One-sentence summary of what this release focuses on.\n\n## What's New\n\n[2-4 sentence narrative covering the biggest features and fixes. \nDescribe what changed and what users can now do. Use active voice. Be factual but upbeat.]\n\n## Highlights\n\n### [Feature/Fix Category]\n**[PR Title rephrased as a clear description of the change]**\n[1-2 sentences expanding on the PR description. Explain what changed and what users can now do differently. \nIf the PR body has useful context, distill it. If empty, infer from the title.]\n\n[Repeat for each significant PR — skip pure chores/dep bumps unless noteworthy]\n\n## Bug Fixes & Reliability\n\n[Bullet list of fixes, each with a brief impact statement]\n\n## Under the Hood\n\n[Brief paragraph or bullet list covering refactors, maintenance, and dep updates — \nkeep it light, acknowledge the work without boring the reader]\n\n## Contributors\n\nA huge thank you to everyone who made this release happen: [list @handles — exclude bots like @dependabot]\n\n---\n**Full changelog**: [GitHub Release link]\n```\n\n### 4. Tone & Style Guidelines\n\n- **Lead with what changed**: \"You can now...\" or \"Forge now...\" beats \"We added...\"\n- **Be specific**: Name the feature and describe what it does, not just the category\n- **Be informative, not marketty**: Avoid vague adjectives like \"seamless\", \"smarter\", \"blazing\", \"powerful\", \"rock-solid\". Instead, state the concrete fact (e.g. \"editor no longer spawns a git process on every keystroke\" beats \"blazing-fast editor\")\n- **Enthusiasm through substance**: Let the actual improvement speak for itself. Use active, direct language.\n- **Short paragraphs**: Max 3 sentences per block\n- **Skip internal jargon**: Translate crate names and internal concepts into plain language\n- **Celebrate contributors**: Name them by handle\n- **Tagline formula**: `[Version] — [Factual Theme Description]` (e.g. \"v1.32.0 — Terminal Context, File Drop Support, Windows Performance\")\n- **No implementation details**: Do not mention internal module names, struct names, function names, crate names, or how something was implemented. Focus purely on what the user experiences or gains.\n- **No PR/issue references**: Do not include PR numbers, issue numbers, or links to GitHub PRs/issues in the release notes. Focus on the changes themselves, not their tracking identifiers.\n\n### 5. Contributors Filter\n\nOnly include **external contributors** in the Contributors section — exclude the core team:\n- `@tusharmath`\n- `@amitksingh1490`\n- `@laststylebender14`\n- Bots (e.g. `@dependabot`)\n\nIf no external contributors exist, omit the Contributors section entirely.\n\n### 6. Validate Length\n\nAfter writing the release notes, run the bundled validation script to confirm the output is under 2000 characters:\n\n```bash\necho \"<release notes>\" | bash .forge/skills/write-release-notes/scripts/validate-release-notes.sh\n```\n\nIf it prints `FAIL`, trim the draft and re-run until it prints `PASS`:\n- Remove the Under the Hood section first\n- Consolidate Bug Fixes into a shorter bullet list\n- Shorten individual PR descriptions to one tight sentence\n- Remove the least impactful Highlights entries\n\n### 7. Output\n\nPrint the final release notes directly in the chat. Do not write to a file unless the user explicitly asks.\n\n## Notes\n\n- The script handles ANSI color codes injected by `gh` CLI automatically.\n- PRs not found (closed without merge, private, etc.) are silently skipped.\n- If the release has no linked PRs in its body, fall back to listing commits between tags:\n  ```bash\n  gh api repos/<owner>/<repo>/compare/<prev_tag>...<version> --jq '.commits[].commit.message'\n  ```\n","category":".forge","tokens":1395},{"name":"SKILL.md","path":"crates/forge_repo/src/skills/execute-plan/SKILL.md","title":"execute-plan Skill","content":"---\nname: execute-plan\ndescription: Execute structured task plans with status tracking. Use when the user provides a plan file path in the format `plans/{current-date}-{task-name}-{version}.md` or explicitly asks you to execute a plan file.\n---\n\n# Execute Plan\n\nExecute structured task plans with automatic status tracking and progress updates.\n\n## Commitment to Completion\n\nWhen a plan is provided, **all tasks in the plan must be completed**. Before starting execution, recite:\n\n> \"I will execute this plan to completion. All the 20 tasks will be addressed and marked as DONE.\"\n\n## Execution Steps\n\n**STEP 1**: Recite the commitment to complete all tasks in the plan.\n\n**STEP 2**: Read the entire plan file to identify pending tasks based on `task_status`.\n\n**STEP 3**: Announce the next pending task and update its status to `IN_PROGRESS` in the plan file.\n\n**STEP 4**: Execute all actions required to complete the task and mark the task status to `DONE` in the plan file.\n\n**STEP 5**: Repeat from Step 3 until all tasks are marked as `DONE`.\n\n**STEP 6**: Re-read the plan file to verify all tasks are completed before announcing completion.\n\n## Task Status Format\n\nUse these status indicators in the plan file:\n\n```\n[ ]: PENDING\n[~]: IN_PROGRESS\n[x]: DONE\n[!]: FAILED\n```\n\n## Example Usage\n\n1. User provides: \"Execute plan at plans/2025-11-23-refactor-auth-v1.md\"\n2. Recite commitment: \"I will execute this plan to completion...\"\n3. Read the plan file\n4. Find first `[ ]` (PENDING) task\n5. Update to `[~]` (IN_PROGRESS)\n6. Execute the task\n7. Update to `[x]` (DONE)\n8. Move to next PENDING task\n9. Repeat until all tasks appear DONE\n10. Re-read plan file to verify completion\n11. Announce completion\n","category":"crates","tokens":426}]}