diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..3468862 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,26 @@ +name: Release Please + +# Maintains a standing release PR that bumps every version file + CHANGELOG from +# Conventional Commits. Merging that PR tags vX.Y.Z and cuts a GitHub Release; +# the existing mcp-server-image.yml then builds/publishes the Docker image on the v* tag. +on: + push: + branches: [main] + +permissions: + contents: write + pull-requests: write + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: googleapis/release-please-action@v4 + with: + # A PAT or GitHub App token in RELEASE_PLEASE_TOKEN lets the pushed v* tag + # trigger mcp-server-image.yml. The default GITHUB_TOKEN also works for opening + # the release PR, but tags it pushes will NOT trigger that workflow (GitHub's + # recursion guard) -- see the "Versioning & Releases" section in the README. + token: ${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }} + config-file: release-please-config.json + manifest-file: .release-please-manifest.json diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..37fcefa --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "1.0.0" +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ec09533 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,31 @@ +# Changelog + +All notable changes to this project are documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +Releases are automated with [release-please](https://github.com/googleapis/release-please); +entries are generated from [Conventional Commit](https://www.conventionalcommits.org) messages. + +## [1.0.0] - 2026-05-27 + +Initial public release of the **ai-bank** catalog and tooling. + +### Added + +- **Catalog of AI-tooling assets** for Rails/Hotwire development: Claude Code skills, + agents, commands, and path-scoped rules under `claude/`, with Codex-native (`codex/`) + and Cursor (`cursor/`) transpilations. +- **Read-only MCP server** (`aibank-mcp`, FastMCP) exposing the catalog over stdio and + streamable HTTP, with `search`, `list_*`/`get_*`, and `get_rules_for_path` tools, JSON + resources, and the command set surfaced as MCP prompts. +- **Grounded chat web app** (`aibank-web`, FastAPI) that answers natural-language + questions strictly from the catalog and cites its sources, reusing the MCP server's + in-process catalog. +- **Claude Code plugin** (`ai-bank`) and the `launchpadlab` plugin marketplace for + one-command connection to the hosted MCP server behind Cloudflare Access. +- **Container image and CI**: multi-arch Docker image published to GHCR, plugin-manifest + validation, and server lint/test workflows. + +[1.0.0]: https://github.com/LaunchPadLab/ai-bank/releases/tag/v1.0.0 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..07c0617 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 LaunchPadLab + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index a55b215..be3f403 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ A centralized repository of AI tooling resources -- skills, agents, rules, Docke **Usage** - [Getting Started](#getting-started) - [Contributing](#contributing) +- [Versioning & Releases](#versioning--releases) --- @@ -502,6 +503,59 @@ The easiest way to connect Claude Code to the hosted server is the **`ai-bank` p On enable, Claude Code prompts for a Cloudflare Access **service token** (Client ID + Secret, from the team secrets manager); the secret is stored in your OS keychain. To auto-enable it for a team, add the marketplace and `enabledPlugins` to a project's `.claude/settings.json` -- see [`plugins/ai-bank/README.md`](plugins/ai-bank/README.md). Non-plugin clients (Cursor, Codex) and local stdio runs still use the manual config below. +#### Connect a CLI to the hosted server manually + +The hosted instance sits behind **Cloudflare Access**. A browser login uses a `@launchpadlab.com` one-time PIN, but an MCP client can't complete that interactive flow -- so clients authenticate with a header credential instead. Two options: + +**Option A -- Cloudflare service token (recommended; persistent).** Get the Client ID + Secret from the team secrets manager, then add the server over HTTP: + +```bash +claude mcp add --transport http ai-bank https://ai-bank.launchpadlab.app/mcp \ + --header "CF-Access-Client-Id: .access" \ + --header "CF-Access-Client-Secret: " +``` + +Or commit/edit `.mcp.json` (Cursor `.cursor/mcp.json` uses the same shape): + +```jsonc +{ "mcpServers": { "ai-bank": { + "type": "http", + "url": "https://ai-bank.launchpadlab.app/mcp", + "headers": { + "CF-Access-Client-Id": ".access", + "CF-Access-Client-Secret": "" + } +} } } +``` + +One service token per person makes per-user revocation easy. + +**Option B -- `cloudflared` access token (works with the OTP-only policy; expires).** No extra Cloudflare setup, but the token is short-lived and must be refreshed: + +```bash +cloudflared access login https://ai-bank.launchpadlab.app/mcp # browser -> @launchpadlab.com OTP +cloudflared access token --app=https://ai-bank.launchpadlab.app # prints a JWT +``` + +Add the JWT to the client as a `cf-access-token: ` header (same `headers` block as above), and re-run the two commands when it expires. + +**Cursor** -- add the server in `.cursor/mcp.json` (project-scoped) or `~/.cursor/mcp.json` (global). It uses the same schema as Claude Code's `.mcp.json`: + +```jsonc +{ "mcpServers": { "ai-bank": { + "type": "http", + "url": "https://ai-bank.launchpadlab.app/mcp", + "headers": { + "CF-Access-Client-Id": ".access", + "CF-Access-Client-Secret": "" + } +} } } +``` + +After saving, open **Cursor Settings -> MCP** and confirm `ai-bank` shows as connected (toggle it on if needed). For the `cloudflared` route (Option B), swap the two `CF-Access-*` headers for a single `cf-access-token: ` header. + +**Codex CLI** -- Codex is stdio-first and its remote-HTTP support is version-dependent, so the hosted URL may not work reliably; if it does in your version, configure it in `~/.codex/config.toml` with the same `CF-Access-*` headers. Otherwise use the local stdio setup below ("Run it"), which sidesteps Cloudflare Access entirely. + **Tools** -- progressive disclosure, so `search`/`list_*` return lightweight summaries and `get_*` return full bodies: | Tool | Purpose | @@ -1019,3 +1073,23 @@ ln -s /path/to/ai-bank/cursor/rules/hipaa-security /path/to/project/.cursor/rule - Keep SKILL.md bodies under 500 lines; move detailed content to `references/` files - Descriptions in frontmatter are the primary mechanism for AI triggering -- make them specific and include use-case examples - Test skills and agents on real tasks before contributing + +--- + +## Versioning & Releases + +This repository follows [Semantic Versioning](https://semver.org). All published components -- the `aibank-mcp` MCP server, the `aibank-web` chat app, and the `ai-bank` Claude Code plugin -- share a **single unified version**, with the full history in [`CHANGELOG.md`](CHANGELOG.md). + +Releases are automated with [release-please](https://github.com/googleapis/release-please). Each merge to `main` updates a standing **release pull request** that bumps the version across `server/pyproject.toml`, both `server/src/*/__init__.py` files, and `plugins/ai-bank/.claude-plugin/plugin.json`, and regenerates the changelog. Merging that PR tags `vX.Y.Z`, publishes a GitHub Release, and triggers the multi-arch Docker build (`ghcr.io/launchpadlab/aibank-mcp:X.Y.Z`). + +Because the version bump and changelog are derived from commit history, **write commit and PR-title subjects as [Conventional Commits](https://www.conventionalcommits.org)**: + +| Prefix | Effect | Example | +|---|---|---| +| `fix:` | patch (`x.y.Z`) | `fix: correct rule path matching` | +| `feat:` | minor (`x.Y.0`) | `feat: add search ranking by recency` | +| `feat!:` or a `BREAKING CHANGE:` footer | major (`X.0.0`) | `feat!: drop stdio transport` | + +Commits without a recognized type are omitted from the changelog. This convention is recommended, not enforced by CI. + +> **Maintainer note:** so that the tag release-please pushes triggers the Docker publish workflow, add a fine-grained PAT or GitHub App token as the `RELEASE_PLEASE_TOKEN` repository secret (Contents + Pull requests: read/write). Without it, releases still work but the image must be built from the tag manually. See [`server/README.md`](server/README.md) for image details. diff --git a/plugins/ai-bank/.claude-plugin/plugin.json b/plugins/ai-bank/.claude-plugin/plugin.json index 9c28501..5406c20 100644 --- a/plugins/ai-bank/.claude-plugin/plugin.json +++ b/plugins/ai-bank/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "ai-bank", "displayName": "AI-Bank Catalog", - "version": "0.1.0", + "version": "1.0.0", "description": "Read-only MCP access to the ai-bank catalog of Rails/Hotwire skills, agents, and rules. Search and fetch assets on demand; ask which rules apply to a file before editing.", "author": { "name": "LaunchPadLab" }, "homepage": "https://github.com/LaunchPadLab/ai-bank", diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..c507246 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "release-type": "simple", + "include-v-in-tag": true, + "include-component-in-tag": false, + "changelog-sections": [ + { "type": "feat", "section": "Features" }, + { "type": "fix", "section": "Bug Fixes" }, + { "type": "perf", "section": "Performance Improvements" }, + { "type": "docs", "section": "Documentation" }, + { "type": "refactor", "section": "Code Refactoring" }, + { "type": "chore", "section": "Miscellaneous", "hidden": true } + ], + "packages": { + ".": { + "package-name": "ai-bank", + "extra-files": [ + { "type": "json", "path": "plugins/ai-bank/.claude-plugin/plugin.json", "jsonpath": "$.version" }, + { "type": "generic", "path": "server/pyproject.toml" }, + { "type": "generic", "path": "server/src/aibank_mcp/__init__.py" }, + { "type": "generic", "path": "server/src/aibank_web/__init__.py" } + ] + } + } +} diff --git a/server/pyproject.toml b/server/pyproject.toml index fea9e8e..414f7d1 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "aibank-mcp" -version = "0.1.0" +version = "1.0.0" # x-release-please-version description = "MCP server exposing the ai-bank Skills/Agents/Rules knowledge base (read-only)." readme = "README.md" requires-python = ">=3.10" diff --git a/server/src/aibank_mcp/__init__.py b/server/src/aibank_mcp/__init__.py index fa0c29e..d7f3bc5 100644 --- a/server/src/aibank_mcp/__init__.py +++ b/server/src/aibank_mcp/__init__.py @@ -5,6 +5,6 @@ instead of copying files between projects. """ -__version__ = "0.1.0" +__version__ = "1.0.0" # x-release-please-version __all__ = ["__version__"] diff --git a/server/src/aibank_web/__init__.py b/server/src/aibank_web/__init__.py index 152d8fd..8d0c8be 100644 --- a/server/src/aibank_web/__init__.py +++ b/server/src/aibank_web/__init__.py @@ -8,4 +8,4 @@ from __future__ import annotations -__version__ = "0.1.0" +__version__ = "1.0.0" # x-release-please-version