diff --git a/.changeset/README.md b/.changeset/README.md index 54ce920..813940c 100644 --- a/.changeset/README.md +++ b/.changeset/README.md @@ -2,4 +2,4 @@ This directory contains [**Changesets**](https://github.com/changesets/changesets) which are markdown files that describe package changes for the next release. -For guidance on when and how to add changesets, checkout the [Maintainer's Guide](../.github/maintainers_guide.md#-updating-changesets). +For guidance on when and how to add changesets, checkout the [Maintainer's Guide](../.github/maintainers_guide.md#updating-changesets). diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 251a4ca..e11acca 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -8,4 +8,4 @@ Our goal is to maintain a safe, helpful and friendly community for everyone, reg This code and related procedures also apply to unacceptable behavior occurring outside the scope of community activities, in all community venues (online and in-person) as well as in all one-on-one communications, and anywhere such behavior has the potential to adversely affect the safety and well-being of community members. -For more information on our code of conduct, please visit [https://slackhq.github.io/code-of-conduct](https://slackhq.github.io/code-of-conduct) \ No newline at end of file +For more information on our code of conduct, please visit [https://slackhq.github.io/code-of-conduct](https://slackhq.github.io/code-of-conduct) diff --git a/.github/contributing.md b/.github/contributing.md index 4f7eabb..bb1c674 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -6,27 +6,30 @@ well. There are many ways you can contribute! :heart: -### Bug Reports and Fixes :bug: -- If you find a bug, please search for it in the [Issues](https://github.com/slackapi/slack-skills-plugin/issues), and if it isn't already tracked, - [create a new issue](https://github.com/slackapi/slack-skills-plugin/issues/new). Fill out the "Bug Report" section of the issue template. Even if an Issue is closed, feel free to comment and add details, it will still - be reviewed. -- Issues that have already been identified as a bug (note: able to reproduce) will be labelled `bug`. -- If you'd like to submit a fix for a bug, [send a Pull Request](#creating_a_pull_request) and mention the Issue number. - - Include tests that isolate the bug and verifies that it was fixed. - -### New Features :bulb: -- If you'd like to add new functionality to this project, describe the problem you want to solve in a [new Issue](https://github.com/slackapi/slack-skills-plugin/issues/new). -- Issues that have been identified as a feature request will be labelled `enhancement`. -- If you'd like to implement the new feature, please wait for feedback from the project - maintainers before spending too much time writing the code. In some cases, `enhancement`s may - not align well with the project objectives at the time. - -### Tests :mag:, Documentation :books:, Miscellaneous :sparkles: -- If you'd like to improve the tests, you want to make the documentation clearer, you have an - alternative implementation of something that may have advantages over the way its currently - done, or you have any other change, we would be happy to hear about it! - - If its a trivial change, go ahead and [send a Pull Request](#creating_a_pull_request) with the changes you have in mind. - - If not, [open an Issue](https://github.com/slackapi/slack-skills-plugin/issues/new) to discuss the idea first. +## Bug Reports and Fixes :bug + +- If you find a bug, please search for it in the [Issues](https://github.com/slackapi/slack-skills-plugin/issues), and if it isn't already tracked, + [create a new issue](https://github.com/slackapi/slack-skills-plugin/issues/new). Fill out the "Bug Report" section of the issue template. Even if an Issue is closed, feel free to comment and add details, it will still + be reviewed. +- Issues that have already been identified as a bug (note: able to reproduce) will be labelled `bug`. +- If you'd like to submit a fix for a bug, [send a Pull Request](#creating-a-pull-request) and mention the Issue number. + - Include tests that isolate the bug and verifies that it was fixed. + +### New Features :bulb + +- If you'd like to add new functionality to this project, describe the problem you want to solve in a [new Issue](https://github.com/slackapi/slack-skills-plugin/issues/new). +- Issues that have been identified as a feature request will be labelled `enhancement`. +- If you'd like to implement the new feature, please wait for feedback from the project + maintainers before spending too much time writing the code. In some cases, `enhancement`s may + not align well with the project objectives at the time. + +### Tests :mag:, Documentation :books:, Miscellaneous :sparkles + +- If you'd like to improve the tests, you want to make the documentation clearer, you have an + alternative implementation of something that may have advantages over the way its currently + done, or you have any other change, we would be happy to hear about it! + - If its a trivial change, go ahead and [send a Pull Request](#creating-a-pull-request) with the changes you have in mind. + - If not, [open an Issue](https://github.com/slackapi/slack-skills-plugin/issues/new) to discuss the idea first. If you're new to our project and looking for some way to make your first contribution, look for Issues labelled `good first contribution`. @@ -39,7 +42,7 @@ For your contribution to be accepted: - [x] The test suite must be complete and pass. - [x] The changes must be approved by code review. - [x] Commits should be atomic and messages must be descriptive. Related issues should be mentioned by Issue number. -- [x] User-facing changes include a changeset (run `npx changeset add`). See [Updating Changesets](./maintainers_guide.md#-updating-changesets) for the format; releases are automated from these. +- [x] User-facing changes include a changeset (run `npx changeset add`). See [Updating Changesets](./maintainers_guide.md#updating-changesets) for the format; releases are automated from these. If the contribution doesn't meet the above criteria, you may fail our automated checks or a maintainer will discuss it with you. You can continue to improve a Pull Request by adding commits to the branch from which the PR was created. @@ -47,14 +50,14 @@ If the contribution doesn't meet the above criteria, you may fail our automated ## Creating a Pull Request -1. :fork_and_knife: Fork the repository on GitHub. -2. :runner: Clone/fetch your fork to your local development machine. It's a good idea to run the tests just - to make sure everything is in order. -3. :herb: Create a new branch and check it out. -4. :crystal_ball: Make your changes and commit them locally. Magic happens here! -5. :arrow_heading_up: Push your new branch to your fork. (e.g. `git push username fix-issue-16`). -6. :inbox_tray: Open a Pull Request on github.com from your new branch on your fork to `main` in this - repository. +1. :fork_and_knife: Fork the repository on GitHub. +2. :runner: Clone/fetch your fork to your local development machine. It's a good idea to run the tests just + to make sure everything is in order. +3. :herb: Create a new branch and check it out. +4. :crystal_ball: Make your changes and commit them locally. Magic happens here! +5. :arrow_heading_up: Push your new branch to your fork. (e.g. `git push username fix-issue-16`). +6. :inbox_tray: Open a Pull Request on github.com from your new branch on your fork to `main` in this + repository. ## Maintainers diff --git a/.github/maintainers_guide.md b/.github/maintainers_guide.md index ba13946..51d0738 100644 --- a/.github/maintainers_guide.md +++ b/.github/maintainers_guide.md @@ -31,10 +31,10 @@ brew install pyenv Install necessary Python runtime for development/testing. ```sh -$ pyenv install 3.14 # select the latest patch version -$ pyenv local 3.14 +pyenv install 3.14 # select the latest patch version +pyenv local 3.14 -$ pyenv rehash +pyenv rehash ``` Then, you can create a new Virtual Environment this way: @@ -62,7 +62,7 @@ make install ``` The tests read configuration from environment variables. Copy the example file -and fill in what you need — each variable is documented inline, and the +and fill in what you need. Each variable is documented inline, and the `Makefile` auto-loads `.env`: ```sh @@ -73,11 +73,15 @@ vim .env ### Running the tests -Always use the `make` targets — never invoke `pytest`, `ruff`, or `python` +Always use the `make` targets, never invoke `pytest`, `ruff`, `python`, or other tools directly. The targets manage the virtualenv, load `.env`, and set up the test dependencies for you. +Run `make help` to list every target with its description (read straight from the +`Makefile`, so it's always current). The ones you'll reach for most: + ```sh +make help # list all targets with their descriptions make test-unit # fast structural + frontmatter checks (this is what CI runs) make test-eval # LLM-judged skill evaluations (local only) make test # both @@ -87,10 +91,12 @@ make typecheck # Mypy static type checks ``` Markdown linting is powered by [rumdl](https://github.com/rvben/rumdl), a -markdownlint-compatible Rust linter. It validates `skills/`, `commands/`, -`README.md`, and `AGENTS.md`. Rules and disabled checks are configured under -`[tool.rumdl]` in `pyproject.toml` — tune that section when a new skill trips a -rule that isn't worth enforcing. +markdownlint-compatible Rust linter. It validates the plugin's authored +markdown — `skills/`, `commands/`, `README.md`, `AGENTS.md`, and the +contributor-facing `.github/` docs. Rules, disabled checks, and the `include` +list of linted files are configured under `[tool.rumdl]` in `pyproject.toml`; +tune that section when a new file or skill trips a rule that isn't worth +enforcing. ### Testing in Claude Code @@ -101,7 +107,7 @@ Load your local changes into Claude Code for a single session with the claude --plugin-dir ./ ``` -This loads the `slack` plugin from your checkout — its skills and commands, and +This loads the `slack` plugin from your checkout: its skills and commands, and the HTTP MCP server from `.mcp.json`. If you already have the published `slack` plugin installed, the local copy takes precedence **for that session only**: nothing is written to your settings, and the installed version is @@ -134,7 +140,7 @@ uninstall, in addition to removing the virtualenv and other generated files.) Follow the [conventional commit specification][conv-commits]. PR titles and commit messages use prefixes like `feat:`, `fix:`, `chore:`, `docs:`, etc. First letter after the prefix is lowercase unless it's a proper noun. -### 🎁 Updating Changesets +### Updating Changesets This project uses [Changesets](https://github.com/changesets/changesets) to track changes and automate releases. @@ -160,7 +166,7 @@ Updates to documentation, tests, or CI might not require new entries. When a PR containing changesets is merged to `main`, a different PR is opened or updated using [changesets/action](https://github.com/changesets/action) which consumes the pending changesets, bumps the package version, and updates the `CHANGELOG` in preparation to release. -### 🚀 Releases +### Releases Releasing can feel intimidating at first, but don't fret! Venture on! @@ -180,8 +186,7 @@ New official package versions are published when the release PR created from cha ### CODEOWNERS -All files are owned by `@slackapi/platform-devxp`. Any PR to this repo will -automatically request review from this team. +Owners are defined in [`.github/CODEOWNERS`](CODEOWNERS). Any PR to this repo automatically requests review from this team. ### Dependabot @@ -196,14 +201,14 @@ Patch and minor updates are auto-approved and auto-merged via the - Feature requests for new skills should be discussed in the issue before implementation begins. - Labels: - - `bug` — confirmed defects - - `enhancement` — feature requests and new functionality - - `docs` — documentation-only changes - - `test` — test-only changes - - `build` — CI, GitHub Actions, and build/compilation processes - - `chore` — repo structure, required files, release scaffolding, general maintenance - - `dependencies` — dependency updates (Dependabot applies this automatically) - - `security` — vulnerability fixes, hardening, and security audit findings + - `bug`: confirmed defects + - `enhancement`: feature requests and new functionality + - `docs`: documentation-only changes + - `test`: test-only changes + - `build`: CI, GitHub Actions, and build/compilation processes + - `chore`: repo structure, required files, release scaffolding, general maintenance + - `dependencies`: dependency updates (Dependabot applies this automatically) + - `security`: vulnerability fixes, hardening, and security audit findings (apply alongside `bug`/`build`/`dependencies` as appropriate) --- diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 0ce24f2..55919e5 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,18 +1,18 @@ ### Summary -(Please describe the goal of this pull request and mention any related issue numbers) + ### Preview -(Add screenshots, GIFs, or recordings that show the changes) + ### Testing -(List the steps used to verify these changes) + ### Notes -(Add any additional context, trade-offs, or follow-up items) + ### Requirements diff --git a/AGENTS.md b/AGENTS.md index db981a7..d383bef 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,41 +4,46 @@ This plugin integrates Slack with Ai tools, providing tools to search, read, and ## Commands -- `/slack:summarize-channel ` — Summarize recent activity in a Slack channel -- `/slack:find-discussions ` — Find discussions about a specific topic across Slack channels -- `/slack:draft-announcement ` — Draft a well-formatted Slack announcement and save it as a draft -- `/slack:standup` — Generate a standup update based on your recent Slack activity -- `/slack:channel-digest ` — Get a digest of recent activity across multiple Slack channels +- `/slack:summarize-channel `: Summarize recent activity in a Slack channel +- `/slack:find-discussions `: Find discussions about a specific topic across Slack channels +- `/slack:draft-announcement `: Draft a well-formatted Slack announcement and save it as a draft +- `/slack:standup`: Generate a standup update based on your recent Slack activity +- `/slack:channel-digest `: Get a digest of recent activity across multiple Slack channels ## Development Commands Requires Python 3.14+. Run `make install` before first use to set up the virtual environment and test dependencies. -**Always use the `make` targets — never invoke `python`, `pytest`, or `ruff` directly.** The targets manage the virtualenv for you; running the underlying tools by hand skips that setup and will behave differently. (The test suite loads `.env` itself, so env vars are available either way — see below.) If a `make` command is broken or missing something you need, fix the `Makefile` rather than working around it with the raw command. +**Always use the make targets rather than invoking python, pytest, ruff, or other tools directly.** The targets manage the virtualenv for you; running the underlying tools by hand skips that setup and will behave differently. If a `make` command is broken or missing something you need, fix the `Makefile` rather than working around it with the raw command. + +Run `make help` for the full list of targets and what each does. The common ones: | Command | Purpose | |---------|---------| -| `make install` | Full setup: venv + deps | -| `make lint` | Ruff (Python) + rumdl (Markdown) linter checks | -| `make format` | Auto-format: Ruff for Python, rumdl --fix for Markdown | -| `make typecheck` | Mypy static type checks | -| `make test-unit` | Fast validation tests (pytest) | -| `make test-eval` | LLM-judged tests (runs DeepEval against Gemini) | -| `make test` | Both unit + eval tests | -| `make clean` | Remove .venv | +| `make help` | Show this help message | +| `make install` | Set up everything (venv + deps) | +| `make lint` | Run linter checks (ruff for Python, rumdl for Markdown) | +| `make format` | Auto-format code (ruff for Python, rumdl for Markdown) | +| `make typecheck` | Run mypy static type checks | +| `make test-unit` | Run structural/unit validation tests | +| `make test-eval` | Run LLM-judged tests (DeepEval against Gemini) | +| `make test` | Run all tests (unit + eval) | +| `make clean` | Remove virtualenv and local Cursor install | | `make cursor-install` | Install this plugin into a local Cursor for development | | `make cursor-uninstall` | Uninstall this plugin from the local Cursor install | -The LLM tests read at least one Gemini API key (required — the eval suite fails when none is set) and `SLACK_MCP_TOKEN` (a Slack MCP bearer token; the MCP tool-selection test is skipped when it's unset). To spread requests across the free-tier quota and avoid `RESOURCE_EXHAUSTED`, any env var whose name starts with `GEMINI_API_KEY` (e.g. `GEMINI_API_KEY`, `GEMINI_API_KEY_BOB`) contributes a key to a pool (blank values are skipped), and each eval request picks one at random. The DeepEval judge model defaults to `gemini-3.1-flash-lite`, overridable via `GEMINI_MODEL_NAME`. Copy `.env.example` to `.env` and fill in values — the test suite loads `.env` from the repo root via `python-dotenv` (`tests/config.py`), so values load the same however tests are launched. Real environment variables take precedence over `.env`, so you can also override inline, e.g. `GEMINI_MODEL_NAME= make test-eval`. +See the [maintainers guide](.github/maintainers_guide.md#local-development--testing) for local development and testing setup. + +Eval tests (`make test-eval`) need a Gemini API key and, for the MCP tool-selection test, `SLACK_MCP_TOKEN`. Copy `.env.example` to `.env` and fill in values; each variable is documented inline there, and the `Makefile` auto-loads `.env`. ## Cross-Skill References When one `SKILL.md` references another skill (e.g., to delegate a step instead of duplicating content), follow these rules: - Use the backticked `plugin:skill` form, e.g. `` `slack:slack-cli` ``. -- When pointing at a specific step, include the step's heading text, not just the number — references survive future reordering. +- When pointing at a specific step, include the step's heading text, not just the number, so references survive future reordering. - Add a sentence of prose explaining what the referenced section does and why you're delegating to it. -- Don't use markdown anchor links (`[text](#step-1)`), `@`-include syntax (`@path/to/SKILL.md`), or bare file paths — none are idiomatic in installed skills, and `@`-includes force-load context. +- Don't use markdown anchor links (`[text](#step-1)`), `@`-include syntax (`@path/to/SKILL.md`), or bare file paths: none are idiomatic in installed skills, and `@`-includes force-load context. See `skills/create-slack-app/SKILL.md` Step 1a for an example. @@ -46,8 +51,8 @@ See `skills/create-slack-app/SKILL.md` Step 1a for an example. Two test layers validate skills: -1. **Unit** (`tests/unit/`) — validates frontmatter fields, naming, and markdown structure. Fast, runs in CI on every PR. -2. **Eval** (`tests/eval/`) — LLM-judged tests that use a Gemini model. `tests/eval/test_tool_selection.py` asks the model to pick the expected tool/skill for each of a set of prompts. Because Gemini's free tier caps at 15 requests/minute, the test sleeps ~5s between scenarios (see its `teardown_method`) to stay under the limit. +1. **Unit** (`tests/unit/`): validates frontmatter fields, naming, and markdown structure. Fast, runs in CI on every PR. +2. **Eval** (`tests/eval/`): LLM-judged tests that use a Gemini model. `tests/eval/test_tool_selection.py` asks the model to pick the expected tool/skill for each of a set of prompts. Because Gemini's free tier caps at 15 requests/minute, the test sleeps ~5s between scenarios (see its `teardown_method`) to stay under the limit. To add an eval scenario, append a `Scenario` (prompt + expected tool) to `SCENARIOS` in `tests/eval/test_tool_selection.py`. @@ -55,17 +60,17 @@ To add an eval scenario, append a `Scenario` (prompt + expected tool) to `SCENAR GitHub Actions (`.github/workflows/ci-build.yml`) gates every PR with: -- **Lint** — `make lint` (Ruff) -- **Typecheck** — `make typecheck` (mypy) -- **Test** — `make test-unit` (pytest) -- **Eval** — `make test-eval` (DeepEval + Gemini) +- **Lint**: `make lint` +- **Typecheck**: `make typecheck` +- **Test**: `make test-unit` +- **Eval**: `make test-eval` The eval job reads the `GEMINI_API_KEY_*` (e.g. `GEMINI_API_KEY_BOB`, `GEMINI_API_KEY_MIC`) and `SLACK_MCP_TOKEN` repository secrets; it skips on PRs from forks, which don't receive secrets. The workflow also runs nightly on a schedule, and a `notifications` job posts to Slack (via `SLACK_REGRESSION_FAILURES_WEBHOOK_URL`) when a job fails on `main`. ## Releasing -Releases are automated and run in CI — **you never run a release yourself.** Your only release-related task is adding a changeset when a PR makes a user-facing change. +Releases are automated and run in CI: **you never run a release yourself.** Your only release-related task is adding a changeset when a PR makes a user-facing change. -See the [maintainers guide](.github/maintainers_guide.md#-updating-changesets) for the format. +See the [maintainers guide](.github/maintainers_guide.md#updating-changesets) for the format. Everything after that is handled by [changesets](https://github.com/changesets/changesets) and `scripts/changeset_version.sh`: merging to `main` opens a "chore: release" PR, and merging that PR publishes the release. diff --git a/pyproject.toml b/pyproject.toml index 822cb60..b9e7b64 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ tools = [ "rumdl>=0.2,<1.0", "mypy>=1.11,<2.0", "types-PyYAML>=6.0,<7.0", - "types-Markdown>=3.5,<4.0" + "types-Markdown>=3.5,<4.0", ] # This project is installed only to run the test suite; the importable package @@ -49,7 +49,15 @@ indent-style = "space" # rumdl: markdownlint-compatible linter for the plugin's authored markdown. [tool.rumdl] -include = ["skills/**/*.md", "commands/*.md", "README.md", "AGENTS.md"] +include = [ + "skills/**/*.md", + "commands/*.md", + "README.md", + "AGENTS.md", + ".github/maintainers_guide.md", + ".github/contributing.md", + ".github/CODE_OF_CONDUCT.md", +] exclude = [".venv", "node_modules", ".changeset"] respect-gitignore = true # Disable rules that conflict with the skill-authoring style: