diff --git a/README.md b/README.md index fba6959c5..9ee400774 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ Current Socket catalog shape: - `game-dev-skills`: Apple platform game development workflows for native Metal and Metal 4 renderers, GPTK 3/4 routing, MetalFX, GPU asset streaming, experimental neural rendering, SpriteKit, SceneKit, GameplayKit simulation, Game Controller input, Core Haptics feedback, Xcode profiling, game-stack routing, and device-aware validation handoffs - `network-protocol-skills`: modern networking and application-protocol workflows for transport selection, HTTP/3 and QUIC planning, Media over QUIC draft-aware guidance, WebRTC signaling/media/data-channel work, and protocol diagnostics with stack-plugin handoffs - `productivity-skills`: general-purpose maintainer, documentation, Dice MCP job-search with bundled remote MCP config, Codex GUI worktree workflow, automation-design and safe n8n-workflow planning, plus source-bundled docs-audit and code-tracing custom-agent definitions -- `python-skills`: Python runtime and tooling workflows, including local-first agent-service implementation guidance; see the [Python skills expansion plan](./docs/maintainers/python-skills-plugin-plan.md) for maintainer details +- `python-skills`: Python runtime and tooling workflows, including local-first agent services, FastAPI and FastMCP service maintenance, and pytest-based testing; see the [Python skills expansion plan](./docs/maintainers/python-skills-plugin-plan.md) for maintainer details - `reverse-engineering-skills`: artifact triage, preservation, exact-build comparison, decompiler review, Apple Mach-O/runtime/signing/Apple Silicon/dyld/dynamic/kernel research, Cutter/Rizin, Malimite, Ghidra, Hopper, .NET, Unity and IL2CPP, and reproducible security evidence workflows - `server-side-jvm`: server-side JVM, Java, Scala, Google ADK agent-service, Gradle, Maven, SBT, and testing workflow guidance, with future Clojure support planned - `server-side-swift`: server-side Swift bootstrap and guidance sync, Vapor, Hummingbird, persistence, OpenAPI/RPC, SwiftNIO, observability, auth, app sync, Docker, Apple `container` 1.x, persistent `container machine` environments, exact-version Containerization APIs, and Fly.io support plus the source-bundled `server-swift-steward` custom-agent definition diff --git a/ROADMAP.md b/ROADMAP.md index c2461defc..bead77d15 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -170,10 +170,10 @@ Completed - [x] Add `python-skills:python-tooling-style-workflow`. - [x] Add `python-skills:python-ci-workflow`. - [x] Add `python-skills:python-upgrade-workflow`. -- [x] Keep `python-skills:uv-pytest-unit-testing` as the release-compatible pytest workflow name for now. +- [x] Replace `python-skills:uv-pytest-unit-testing` with the broader `python-skills:python-testing-workflow` without a duplicate compatibility surface. - [x] Update Python plugin metadata after the first new skill slice lands. - [x] Run child validation with `uv run scripts/validate_repo_metadata.py`, `uv run pytest`, `uv run ruff check .`, and `uv run mypy .`. -- [ ] Run root metadata validation with `uv run scripts/validate_socket_metadata.py`. +- [x] Run root metadata validation with `uv run scripts/validate_socket_metadata.py`. ### Exit Criteria diff --git a/docs/agents/bundled-subagent-role-candidates.md b/docs/agents/bundled-subagent-role-candidates.md index c2acec088..e2c80e06b 100644 --- a/docs/agents/bundled-subagent-role-candidates.md +++ b/docs/agents/bundled-subagent-role-candidates.md @@ -196,7 +196,7 @@ Evidence: - `plugins/python-skills/skills/python-package-workflow/SKILL.md` - `plugins/python-skills/skills/python-tooling-style-workflow/SKILL.md` - `plugins/python-skills/skills/python-upgrade-workflow/SKILL.md` -- `plugins/python-skills/skills/uv-pytest-unit-testing/SKILL.md` +- `plugins/python-skills/skills/python-testing-workflow/SKILL.md` ### rust-skills: rust-validation-triager diff --git a/docs/architecture/ARCHITECTURE.md b/docs/architecture/ARCHITECTURE.md index cbfda7d77..8e26abd3a 100644 --- a/docs/architecture/ARCHITECTURE.md +++ b/docs/architecture/ARCHITECTURE.md @@ -75,6 +75,7 @@ See [SLICES.md](./SLICES.md) for provable end-to-end code paths. - `skill:apple-dev-skills/avfoundation-media-pipeline-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/avfoundation-media-pipeline-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/bootstrap-swift-package` (codex-skill) at `plugins/apple-dev-skills/skills/bootstrap-swift-package/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/bootstrap-xcode-app-project` (codex-skill) at `plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/SKILL.md` depends on: no declared dependencies. +- `skill:apple-dev-skills/bootstrap-xcode-workspace` (codex-skill) at `plugins/apple-dev-skills/skills/bootstrap-xcode-workspace/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/camera-capture-depth-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/camera-capture-depth-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/choose-macos-virtualization-shape` (codex-skill) at `plugins/apple-dev-skills/skills/choose-macos-virtualization-shape/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/core-animation-layer-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/core-animation-layer-workflow/SKILL.md` depends on: no declared dependencies. @@ -115,8 +116,11 @@ See [SLICES.md](./SLICES.md) for provable end-to-end code paths. - `skill:apple-dev-skills/swiftui-performance-audit` (codex-skill) at `plugins/apple-dev-skills/skills/swiftui-performance-audit/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/sync-swift-package-guidance` (codex-skill) at `plugins/apple-dev-skills/skills/sync-swift-package-guidance/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/sync-xcode-project-guidance` (codex-skill) at `plugins/apple-dev-skills/skills/sync-xcode-project-guidance/SKILL.md` depends on: no declared dependencies. +- `skill:apple-dev-skills/sync-xcode-workspace-guidance` (codex-skill) at `plugins/apple-dev-skills/skills/sync-xcode-workspace-guidance/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/tipkit-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/tipkit-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/tips-helpviewer-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/tips-helpviewer-workflow/SKILL.md` depends on: no declared dependencies. +- `skill:apple-dev-skills/tvos-app-experience-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/tvos-app-experience-workflow/SKILL.md` depends on: no declared dependencies. +- `skill:apple-dev-skills/tvos-media-playback-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/tvos-media-playback-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/video-codec-processing-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/video-codec-processing-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/virtualization-framework-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/virtualization-framework-workflow/SKILL.md` depends on: no declared dependencies. - `skill:apple-dev-skills/vision-coreml-recognition-workflow` (codex-skill) at `plugins/apple-dev-skills/skills/vision-coreml-recognition-workflow/SKILL.md` depends on: no declared dependencies. @@ -171,7 +175,12 @@ See [SLICES.md](./SLICES.md) for provable end-to-end code paths. - `skill:dotnet-skills/aspnet-core-service-workflow` (codex-skill) at `plugins/dotnet-skills/skills/aspnet-core-service-workflow/SKILL.md` depends on: no declared dependencies. - `skill:dotnet-skills/bootstrap-solution` (codex-skill) at `plugins/dotnet-skills/skills/bootstrap-solution/SKILL.md` depends on: no declared dependencies. - `skill:dotnet-skills/build-csharp-project` (codex-skill) at `plugins/dotnet-skills/skills/build-csharp-project/SKILL.md` depends on: no declared dependencies. +- `skill:dotnet-skills/build-dotnet-agent-service` (codex-skill) at `plugins/dotnet-skills/skills/build-dotnet-agent-service/SKILL.md` depends on: no declared dependencies. +- `skill:dotnet-skills/build-falco-web-app` (codex-skill) at `plugins/dotnet-skills/skills/build-falco-web-app/SKILL.md` depends on: no declared dependencies. - `skill:dotnet-skills/build-fsharp-project` (codex-skill) at `plugins/dotnet-skills/skills/build-fsharp-project/SKILL.md` depends on: no declared dependencies. +- `skill:dotnet-skills/build-giraffe-web-app` (codex-skill) at `plugins/dotnet-skills/skills/build-giraffe-web-app/SKILL.md` depends on: no declared dependencies. +- `skill:dotnet-skills/build-oxpecker-web-app` (codex-skill) at `plugins/dotnet-skills/skills/build-oxpecker-web-app/SKILL.md` depends on: no declared dependencies. +- `skill:dotnet-skills/choose-fsharp-web-framework` (codex-skill) at `plugins/dotnet-skills/skills/choose-fsharp-web-framework/SKILL.md` depends on: no declared dependencies. - `skill:dotnet-skills/choose-project-shape` (codex-skill) at `plugins/dotnet-skills/skills/choose-project-shape/SKILL.md` depends on: no declared dependencies. - `skill:dotnet-skills/ci-workflow` (codex-skill) at `plugins/dotnet-skills/skills/ci-workflow/SKILL.md` depends on: no declared dependencies. - `skill:dotnet-skills/diagnose-project` (codex-skill) at `plugins/dotnet-skills/skills/diagnose-project/SKILL.md` depends on: no declared dependencies. @@ -229,6 +238,7 @@ See [SLICES.md](./SLICES.md) for provable end-to-end code paths. - `skill:productivity-skills/codex-gui-worktree-workflow` (codex-skill) at `plugins/productivity-skills/skills/codex-gui-worktree-workflow/SKILL.md` depends on: no declared dependencies. - `skill:productivity-skills/design-agent-automation-workflow` (codex-skill) at `plugins/productivity-skills/skills/design-agent-automation-workflow/SKILL.md` depends on: no declared dependencies. - `skill:productivity-skills/design-agent-eval-workflow` (codex-skill) at `plugins/productivity-skills/skills/design-agent-eval-workflow/SKILL.md` depends on: no declared dependencies. +- `skill:productivity-skills/design-n8n-agent-workflow` (codex-skill) at `plugins/productivity-skills/skills/design-n8n-agent-workflow/SKILL.md` depends on: no declared dependencies. - `skill:productivity-skills/dice-job-search-workflow` (codex-skill) at `plugins/productivity-skills/skills/dice-job-search-workflow/SKILL.md` depends on: no declared dependencies. - `skill:productivity-skills/explain-code-slice` (codex-skill) at `plugins/productivity-skills/skills/explain-code-slice/SKILL.md` depends on: no declared dependencies. - `skill:productivity-skills/maintain-github-repository` (codex-skill) at `plugins/productivity-skills/skills/maintain-github-repository/SKILL.md` depends on: no declared dependencies. @@ -245,15 +255,18 @@ See [SLICES.md](./SLICES.md) for provable end-to-end code paths. - `skill:python-skills/bootstrap-python-mcp-service` (codex-skill) at `plugins/python-skills/skills/bootstrap-python-mcp-service/SKILL.md` depends on: no declared dependencies. - `skill:python-skills/bootstrap-python-service` (codex-skill) at `plugins/python-skills/skills/bootstrap-python-service/SKILL.md` depends on: no declared dependencies. - `skill:python-skills/bootstrap-uv-python-workspace` (codex-skill) at `plugins/python-skills/skills/bootstrap-uv-python-workspace/SKILL.md` depends on: no declared dependencies. +- `skill:python-skills/build-python-agent-service` (codex-skill) at `plugins/python-skills/skills/build-python-agent-service/SKILL.md` depends on: no declared dependencies. - `skill:python-skills/build-python-project` (codex-skill) at `plugins/python-skills/skills/build-python-project/SKILL.md` depends on: no declared dependencies. - `skill:python-skills/choose-python-project-shape` (codex-skill) at `plugins/python-skills/skills/choose-python-project-shape/SKILL.md` depends on: no declared dependencies. - `skill:python-skills/diagnose-python-project` (codex-skill) at `plugins/python-skills/skills/diagnose-python-project/SKILL.md` depends on: no declared dependencies. +- `skill:python-skills/fastapi-service-workflow` (codex-skill) at `plugins/python-skills/skills/fastapi-service-workflow/SKILL.md` depends on: no declared dependencies. +- `skill:python-skills/fastmcp-service-workflow` (codex-skill) at `plugins/python-skills/skills/fastmcp-service-workflow/SKILL.md` depends on: no declared dependencies. - `skill:python-skills/integrate-fastapi-fastmcp` (codex-skill) at `plugins/python-skills/skills/integrate-fastapi-fastmcp/SKILL.md` depends on: no declared dependencies. - `skill:python-skills/python-ci-workflow` (codex-skill) at `plugins/python-skills/skills/python-ci-workflow/SKILL.md` depends on: no declared dependencies. - `skill:python-skills/python-package-workflow` (codex-skill) at `plugins/python-skills/skills/python-package-workflow/SKILL.md` depends on: no declared dependencies. +- `skill:python-skills/python-testing-workflow` (codex-skill) at `plugins/python-skills/skills/python-testing-workflow/SKILL.md` depends on: no declared dependencies. - `skill:python-skills/python-tooling-style-workflow` (codex-skill) at `plugins/python-skills/skills/python-tooling-style-workflow/SKILL.md` depends on: no declared dependencies. - `skill:python-skills/python-upgrade-workflow` (codex-skill) at `plugins/python-skills/skills/python-upgrade-workflow/SKILL.md` depends on: no declared dependencies. -- `skill:python-skills/uv-pytest-unit-testing` (codex-skill) at `plugins/python-skills/skills/uv-pytest-unit-testing/SKILL.md` depends on: no declared dependencies. - `skill:reverse-engineering-skills/analyze-apple-silicon-arm64e` (codex-skill) at `plugins/reverse-engineering-skills/skills/analyze-apple-silicon-arm64e/SKILL.md` depends on: no declared dependencies. - `skill:reverse-engineering-skills/audit-apple-signing-and-containment` (codex-skill) at `plugins/reverse-engineering-skills/skills/audit-apple-signing-and-containment/SKILL.md` depends on: no declared dependencies. - `skill:reverse-engineering-skills/compare-binary-versions` (codex-skill) at `plugins/reverse-engineering-skills/skills/compare-binary-versions/SKILL.md` depends on: no declared dependencies. @@ -287,6 +300,7 @@ See [SLICES.md](./SLICES.md) for provable end-to-end code paths. - `skill:rust-skills/testing-workflow` (codex-skill) at `plugins/rust-skills/skills/testing-workflow/SKILL.md` depends on: no declared dependencies. - `skill:rust-skills/tooling-style-workflow` (codex-skill) at `plugins/rust-skills/skills/tooling-style-workflow/SKILL.md` depends on: no declared dependencies. - `skill:server-side-jvm/build-java-service` (codex-skill) at `plugins/server-side-jvm/skills/build-java-service/SKILL.md` depends on: no declared dependencies. +- `skill:server-side-jvm/build-jvm-agent-service` (codex-skill) at `plugins/server-side-jvm/skills/build-jvm-agent-service/SKILL.md` depends on: no declared dependencies. - `skill:server-side-jvm/build-scala-service` (codex-skill) at `plugins/server-side-jvm/skills/build-scala-service/SKILL.md` depends on: no declared dependencies. - `skill:server-side-jvm/build-tooling-workflow` (codex-skill) at `plugins/server-side-jvm/skills/build-tooling-workflow/SKILL.md` depends on: no declared dependencies. - `skill:server-side-jvm/choose-service-shape` (codex-skill) at `plugins/server-side-jvm/skills/choose-service-shape/SKILL.md` depends on: no declared dependencies. @@ -376,6 +390,7 @@ The structured visual model lives in [architecture.json](./architecture.json). I - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/avfoundation-media-pipeline-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/bootstrap-swift-package/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/SKILL.md`. +- `skill-manifest` evidence from `plugins/apple-dev-skills/skills/bootstrap-xcode-workspace/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/camera-capture-depth-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/choose-macos-virtualization-shape/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/core-animation-layer-workflow/SKILL.md`. @@ -416,8 +431,11 @@ The structured visual model lives in [architecture.json](./architecture.json). I - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/swiftui-performance-audit/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/sync-swift-package-guidance/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/sync-xcode-project-guidance/SKILL.md`. +- `skill-manifest` evidence from `plugins/apple-dev-skills/skills/sync-xcode-workspace-guidance/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/tipkit-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/tips-helpviewer-workflow/SKILL.md`. +- `skill-manifest` evidence from `plugins/apple-dev-skills/skills/tvos-app-experience-workflow/SKILL.md`. +- `skill-manifest` evidence from `plugins/apple-dev-skills/skills/tvos-media-playback-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/video-codec-processing-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/virtualization-framework-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/apple-dev-skills/skills/vision-coreml-recognition-workflow/SKILL.md`. @@ -477,7 +495,12 @@ The structured visual model lives in [architecture.json](./architecture.json). I - `skill-manifest` evidence from `plugins/dotnet-skills/skills/aspnet-core-service-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/dotnet-skills/skills/bootstrap-solution/SKILL.md`. - `skill-manifest` evidence from `plugins/dotnet-skills/skills/build-csharp-project/SKILL.md`. +- `skill-manifest` evidence from `plugins/dotnet-skills/skills/build-dotnet-agent-service/SKILL.md`. +- `skill-manifest` evidence from `plugins/dotnet-skills/skills/build-falco-web-app/SKILL.md`. - `skill-manifest` evidence from `plugins/dotnet-skills/skills/build-fsharp-project/SKILL.md`. +- `skill-manifest` evidence from `plugins/dotnet-skills/skills/build-giraffe-web-app/SKILL.md`. +- `skill-manifest` evidence from `plugins/dotnet-skills/skills/build-oxpecker-web-app/SKILL.md`. +- `skill-manifest` evidence from `plugins/dotnet-skills/skills/choose-fsharp-web-framework/SKILL.md`. - `skill-manifest` evidence from `plugins/dotnet-skills/skills/choose-project-shape/SKILL.md`. - `skill-manifest` evidence from `plugins/dotnet-skills/skills/ci-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/dotnet-skills/skills/diagnose-project/SKILL.md`. @@ -540,6 +563,7 @@ The structured visual model lives in [architecture.json](./architecture.json). I - `skill-manifest` evidence from `plugins/productivity-skills/skills/codex-gui-worktree-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/productivity-skills/skills/design-agent-automation-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/productivity-skills/skills/design-agent-eval-workflow/SKILL.md`. +- `skill-manifest` evidence from `plugins/productivity-skills/skills/design-n8n-agent-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/productivity-skills/skills/dice-job-search-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/productivity-skills/skills/explain-code-slice/SKILL.md`. - `skill-manifest` evidence from `plugins/productivity-skills/skills/maintain-github-repository/SKILL.md`. @@ -557,15 +581,18 @@ The structured visual model lives in [architecture.json](./architecture.json). I - `skill-manifest` evidence from `plugins/python-skills/skills/bootstrap-python-mcp-service/SKILL.md`. - `skill-manifest` evidence from `plugins/python-skills/skills/bootstrap-python-service/SKILL.md`. - `skill-manifest` evidence from `plugins/python-skills/skills/bootstrap-uv-python-workspace/SKILL.md`. +- `skill-manifest` evidence from `plugins/python-skills/skills/build-python-agent-service/SKILL.md`. - `skill-manifest` evidence from `plugins/python-skills/skills/build-python-project/SKILL.md`. - `skill-manifest` evidence from `plugins/python-skills/skills/choose-python-project-shape/SKILL.md`. - `skill-manifest` evidence from `plugins/python-skills/skills/diagnose-python-project/SKILL.md`. +- `skill-manifest` evidence from `plugins/python-skills/skills/fastapi-service-workflow/SKILL.md`. +- `skill-manifest` evidence from `plugins/python-skills/skills/fastmcp-service-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/python-skills/skills/integrate-fastapi-fastmcp/SKILL.md`. - `skill-manifest` evidence from `plugins/python-skills/skills/python-ci-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/python-skills/skills/python-package-workflow/SKILL.md`. +- `skill-manifest` evidence from `plugins/python-skills/skills/python-testing-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/python-skills/skills/python-tooling-style-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/python-skills/skills/python-upgrade-workflow/SKILL.md`. -- `skill-manifest` evidence from `plugins/python-skills/skills/uv-pytest-unit-testing/SKILL.md`. - `codex-plugin-manifest` evidence from `plugins/python-skills/.codex-plugin/plugin.json`. - `skill-manifest` evidence from `plugins/reverse-engineering-skills/skills/analyze-apple-silicon-arm64e/SKILL.md`. - `skill-manifest` evidence from `plugins/reverse-engineering-skills/skills/audit-apple-signing-and-containment/SKILL.md`. @@ -602,6 +629,7 @@ The structured visual model lives in [architecture.json](./architecture.json). I - `skill-manifest` evidence from `plugins/rust-skills/skills/tooling-style-workflow/SKILL.md`. - `codex-plugin-manifest` evidence from `plugins/rust-skills/.codex-plugin/plugin.json`. - `skill-manifest` evidence from `plugins/server-side-jvm/skills/build-java-service/SKILL.md`. +- `skill-manifest` evidence from `plugins/server-side-jvm/skills/build-jvm-agent-service/SKILL.md`. - `skill-manifest` evidence from `plugins/server-side-jvm/skills/build-scala-service/SKILL.md`. - `skill-manifest` evidence from `plugins/server-side-jvm/skills/build-tooling-workflow/SKILL.md`. - `skill-manifest` evidence from `plugins/server-side-jvm/skills/choose-service-shape/SKILL.md`. diff --git a/docs/architecture/architecture.json b/docs/architecture/architecture.json index e7cfc75cc..6dd8eafe1 100644 --- a/docs/architecture/architecture.json +++ b/docs/architecture/architecture.json @@ -1,5 +1,5 @@ { - "detectedAt": "2026-07-19T19:27:23.828783+00:00", + "detectedAt": "2026-07-29T13:33:08.747267+00:00", "detectionSource": "plugin-repo", "evidence": [ { @@ -142,6 +142,10 @@ "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/bootstrap-xcode-workspace/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/camera-capture-depth-workflow/SKILL.md" @@ -302,6 +306,10 @@ "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/sync-xcode-project-guidance/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/sync-xcode-workspace-guidance/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/tipkit-workflow/SKILL.md" @@ -310,6 +318,14 @@ "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/tips-helpviewer-workflow/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/tvos-app-experience-workflow/SKILL.md" + }, + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/tvos-media-playback-workflow/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/apple-dev-skills/skills/video-codec-processing-workflow/SKILL.md" @@ -546,10 +562,30 @@ "kind": "skill-manifest", "path": "plugins/dotnet-skills/skills/build-csharp-project/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/dotnet-skills/skills/build-dotnet-agent-service/SKILL.md" + }, + { + "kind": "skill-manifest", + "path": "plugins/dotnet-skills/skills/build-falco-web-app/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/dotnet-skills/skills/build-fsharp-project/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/dotnet-skills/skills/build-giraffe-web-app/SKILL.md" + }, + { + "kind": "skill-manifest", + "path": "plugins/dotnet-skills/skills/build-oxpecker-web-app/SKILL.md" + }, + { + "kind": "skill-manifest", + "path": "plugins/dotnet-skills/skills/choose-fsharp-web-framework/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/dotnet-skills/skills/choose-project-shape/SKILL.md" @@ -798,6 +834,10 @@ "kind": "skill-manifest", "path": "plugins/productivity-skills/skills/design-agent-eval-workflow/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/productivity-skills/skills/design-n8n-agent-workflow/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/productivity-skills/skills/dice-job-search-workflow/SKILL.md" @@ -866,6 +906,10 @@ "kind": "skill-manifest", "path": "plugins/python-skills/skills/bootstrap-uv-python-workspace/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/python-skills/skills/build-python-agent-service/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/python-skills/skills/build-python-project/SKILL.md" @@ -878,6 +922,14 @@ "kind": "skill-manifest", "path": "plugins/python-skills/skills/diagnose-python-project/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/python-skills/skills/fastapi-service-workflow/SKILL.md" + }, + { + "kind": "skill-manifest", + "path": "plugins/python-skills/skills/fastmcp-service-workflow/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/python-skills/skills/integrate-fastapi-fastmcp/SKILL.md" @@ -892,15 +944,15 @@ }, { "kind": "skill-manifest", - "path": "plugins/python-skills/skills/python-tooling-style-workflow/SKILL.md" + "path": "plugins/python-skills/skills/python-testing-workflow/SKILL.md" }, { "kind": "skill-manifest", - "path": "plugins/python-skills/skills/python-upgrade-workflow/SKILL.md" + "path": "plugins/python-skills/skills/python-tooling-style-workflow/SKILL.md" }, { "kind": "skill-manifest", - "path": "plugins/python-skills/skills/uv-pytest-unit-testing/SKILL.md" + "path": "plugins/python-skills/skills/python-upgrade-workflow/SKILL.md" }, { "kind": "codex-plugin-manifest", @@ -1046,6 +1098,10 @@ "kind": "skill-manifest", "path": "plugins/server-side-jvm/skills/build-java-service/SKILL.md" }, + { + "kind": "skill-manifest", + "path": "plugins/server-side-jvm/skills/build-jvm-agent-service/SKILL.md" + }, { "kind": "skill-manifest", "path": "plugins/server-side-jvm/skills/build-scala-service/SKILL.md" @@ -2014,6 +2070,18 @@ "label": "plugin exposes skill", "to": "target:skill:apple-dev-skills/bootstrap-xcode-app-project" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/apple-dev-skills/skills/bootstrap-xcode-workspace/SKILL.md" + } + ], + "from": "product:apple-dev-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:apple-dev-skills/bootstrap-xcode-workspace" + }, { "evidence": [ { @@ -2494,6 +2562,18 @@ "label": "plugin exposes skill", "to": "target:skill:apple-dev-skills/sync-xcode-project-guidance" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/apple-dev-skills/skills/sync-xcode-workspace-guidance/SKILL.md" + } + ], + "from": "product:apple-dev-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:apple-dev-skills/sync-xcode-workspace-guidance" + }, { "evidence": [ { @@ -2518,6 +2598,30 @@ "label": "plugin exposes skill", "to": "target:skill:apple-dev-skills/tips-helpviewer-workflow" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/apple-dev-skills/skills/tvos-app-experience-workflow/SKILL.md" + } + ], + "from": "product:apple-dev-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:apple-dev-skills/tvos-app-experience-workflow" + }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/apple-dev-skills/skills/tvos-media-playback-workflow/SKILL.md" + } + ], + "from": "product:apple-dev-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:apple-dev-skills/tvos-media-playback-workflow" + }, { "evidence": [ { @@ -3166,6 +3270,30 @@ "label": "plugin exposes skill", "to": "target:skill:dotnet-skills/build-csharp-project" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/dotnet-skills/skills/build-dotnet-agent-service/SKILL.md" + } + ], + "from": "product:dotnet-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:dotnet-skills/build-dotnet-agent-service" + }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/dotnet-skills/skills/build-falco-web-app/SKILL.md" + } + ], + "from": "product:dotnet-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:dotnet-skills/build-falco-web-app" + }, { "evidence": [ { @@ -3178,6 +3306,42 @@ "label": "plugin exposes skill", "to": "target:skill:dotnet-skills/build-fsharp-project" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/dotnet-skills/skills/build-giraffe-web-app/SKILL.md" + } + ], + "from": "product:dotnet-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:dotnet-skills/build-giraffe-web-app" + }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/dotnet-skills/skills/build-oxpecker-web-app/SKILL.md" + } + ], + "from": "product:dotnet-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:dotnet-skills/build-oxpecker-web-app" + }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/dotnet-skills/skills/choose-fsharp-web-framework/SKILL.md" + } + ], + "from": "product:dotnet-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:dotnet-skills/choose-fsharp-web-framework" + }, { "evidence": [ { @@ -3862,6 +4026,18 @@ "label": "plugin exposes skill", "to": "target:skill:productivity-skills/design-agent-eval-workflow" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/productivity-skills/skills/design-n8n-agent-workflow/SKILL.md" + } + ], + "from": "product:productivity-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:productivity-skills/design-n8n-agent-workflow" + }, { "evidence": [ { @@ -4054,6 +4230,18 @@ "label": "plugin exposes skill", "to": "target:skill:python-skills/bootstrap-uv-python-workspace" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/python-skills/skills/build-python-agent-service/SKILL.md" + } + ], + "from": "product:python-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:python-skills/build-python-agent-service" + }, { "evidence": [ { @@ -4090,6 +4278,30 @@ "label": "plugin exposes skill", "to": "target:skill:python-skills/diagnose-python-project" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/python-skills/skills/fastapi-service-workflow/SKILL.md" + } + ], + "from": "product:python-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:python-skills/fastapi-service-workflow" + }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/python-skills/skills/fastmcp-service-workflow/SKILL.md" + } + ], + "from": "product:python-skills", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:python-skills/fastmcp-service-workflow" + }, { "evidence": [ { @@ -4130,37 +4342,37 @@ "evidence": [ { "kind": "skill-directory", - "path": "plugins/python-skills/skills/python-tooling-style-workflow/SKILL.md" + "path": "plugins/python-skills/skills/python-testing-workflow/SKILL.md" } ], "from": "product:python-skills", "kind": "exposes", "label": "plugin exposes skill", - "to": "target:skill:python-skills/python-tooling-style-workflow" + "to": "target:skill:python-skills/python-testing-workflow" }, { "evidence": [ { "kind": "skill-directory", - "path": "plugins/python-skills/skills/python-upgrade-workflow/SKILL.md" + "path": "plugins/python-skills/skills/python-tooling-style-workflow/SKILL.md" } ], "from": "product:python-skills", "kind": "exposes", "label": "plugin exposes skill", - "to": "target:skill:python-skills/python-upgrade-workflow" + "to": "target:skill:python-skills/python-tooling-style-workflow" }, { "evidence": [ { "kind": "skill-directory", - "path": "plugins/python-skills/skills/uv-pytest-unit-testing/SKILL.md" + "path": "plugins/python-skills/skills/python-upgrade-workflow/SKILL.md" } ], "from": "product:python-skills", "kind": "exposes", "label": "plugin exposes skill", - "to": "target:skill:python-skills/uv-pytest-unit-testing" + "to": "target:skill:python-skills/python-upgrade-workflow" }, { "evidence": [ @@ -4558,6 +4770,18 @@ "label": "plugin exposes skill", "to": "target:skill:server-side-jvm/build-java-service" }, + { + "evidence": [ + { + "kind": "skill-directory", + "path": "plugins/server-side-jvm/skills/build-jvm-agent-service/SKILL.md" + } + ], + "from": "product:server-side-jvm", + "kind": "exposes", + "label": "plugin exposes skill", + "to": "target:skill:server-side-jvm/build-jvm-agent-service" + }, { "evidence": [ { @@ -6014,6 +6238,18 @@ "name": "skill:apple-dev-skills/bootstrap-xcode-app-project", "path": "plugins/apple-dev-skills/skills/bootstrap-xcode-app-project/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/bootstrap-xcode-workspace/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:apple-dev-skills/bootstrap-xcode-workspace", + "path": "plugins/apple-dev-skills/skills/bootstrap-xcode-workspace/SKILL.md" + }, { "dependencies": [], "evidence": [ @@ -6494,6 +6730,18 @@ "name": "skill:apple-dev-skills/sync-xcode-project-guidance", "path": "plugins/apple-dev-skills/skills/sync-xcode-project-guidance/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/sync-xcode-workspace-guidance/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:apple-dev-skills/sync-xcode-workspace-guidance", + "path": "plugins/apple-dev-skills/skills/sync-xcode-workspace-guidance/SKILL.md" + }, { "dependencies": [], "evidence": [ @@ -6518,6 +6766,30 @@ "name": "skill:apple-dev-skills/tips-helpviewer-workflow", "path": "plugins/apple-dev-skills/skills/tips-helpviewer-workflow/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/tvos-app-experience-workflow/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:apple-dev-skills/tvos-app-experience-workflow", + "path": "plugins/apple-dev-skills/skills/tvos-app-experience-workflow/SKILL.md" + }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/apple-dev-skills/skills/tvos-media-playback-workflow/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:apple-dev-skills/tvos-media-playback-workflow", + "path": "plugins/apple-dev-skills/skills/tvos-media-playback-workflow/SKILL.md" + }, { "dependencies": [], "evidence": [ @@ -7166,6 +7438,30 @@ "name": "skill:dotnet-skills/build-csharp-project", "path": "plugins/dotnet-skills/skills/build-csharp-project/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/dotnet-skills/skills/build-dotnet-agent-service/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:dotnet-skills/build-dotnet-agent-service", + "path": "plugins/dotnet-skills/skills/build-dotnet-agent-service/SKILL.md" + }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/dotnet-skills/skills/build-falco-web-app/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:dotnet-skills/build-falco-web-app", + "path": "plugins/dotnet-skills/skills/build-falco-web-app/SKILL.md" + }, { "dependencies": [], "evidence": [ @@ -7178,6 +7474,42 @@ "name": "skill:dotnet-skills/build-fsharp-project", "path": "plugins/dotnet-skills/skills/build-fsharp-project/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/dotnet-skills/skills/build-giraffe-web-app/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:dotnet-skills/build-giraffe-web-app", + "path": "plugins/dotnet-skills/skills/build-giraffe-web-app/SKILL.md" + }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/dotnet-skills/skills/build-oxpecker-web-app/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:dotnet-skills/build-oxpecker-web-app", + "path": "plugins/dotnet-skills/skills/build-oxpecker-web-app/SKILL.md" + }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/dotnet-skills/skills/choose-fsharp-web-framework/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:dotnet-skills/choose-fsharp-web-framework", + "path": "plugins/dotnet-skills/skills/choose-fsharp-web-framework/SKILL.md" + }, { "dependencies": [], "evidence": [ @@ -7862,6 +8194,18 @@ "name": "skill:productivity-skills/design-agent-eval-workflow", "path": "plugins/productivity-skills/skills/design-agent-eval-workflow/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/productivity-skills/skills/design-n8n-agent-workflow/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:productivity-skills/design-n8n-agent-workflow", + "path": "plugins/productivity-skills/skills/design-n8n-agent-workflow/SKILL.md" + }, { "dependencies": [], "evidence": [ @@ -8054,6 +8398,18 @@ "name": "skill:python-skills/bootstrap-uv-python-workspace", "path": "plugins/python-skills/skills/bootstrap-uv-python-workspace/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/python-skills/skills/build-python-agent-service/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:python-skills/build-python-agent-service", + "path": "plugins/python-skills/skills/build-python-agent-service/SKILL.md" + }, { "dependencies": [], "evidence": [ @@ -8090,6 +8446,30 @@ "name": "skill:python-skills/diagnose-python-project", "path": "plugins/python-skills/skills/diagnose-python-project/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/python-skills/skills/fastapi-service-workflow/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:python-skills/fastapi-service-workflow", + "path": "plugins/python-skills/skills/fastapi-service-workflow/SKILL.md" + }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/python-skills/skills/fastmcp-service-workflow/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:python-skills/fastmcp-service-workflow", + "path": "plugins/python-skills/skills/fastmcp-service-workflow/SKILL.md" + }, { "dependencies": [], "evidence": [ @@ -8131,36 +8511,36 @@ "evidence": [ { "kind": "skill-manifest", - "path": "plugins/python-skills/skills/python-tooling-style-workflow/SKILL.md" + "path": "plugins/python-skills/skills/python-testing-workflow/SKILL.md" } ], "kind": "codex-skill", - "name": "skill:python-skills/python-tooling-style-workflow", - "path": "plugins/python-skills/skills/python-tooling-style-workflow/SKILL.md" + "name": "skill:python-skills/python-testing-workflow", + "path": "plugins/python-skills/skills/python-testing-workflow/SKILL.md" }, { "dependencies": [], "evidence": [ { "kind": "skill-manifest", - "path": "plugins/python-skills/skills/python-upgrade-workflow/SKILL.md" + "path": "plugins/python-skills/skills/python-tooling-style-workflow/SKILL.md" } ], "kind": "codex-skill", - "name": "skill:python-skills/python-upgrade-workflow", - "path": "plugins/python-skills/skills/python-upgrade-workflow/SKILL.md" + "name": "skill:python-skills/python-tooling-style-workflow", + "path": "plugins/python-skills/skills/python-tooling-style-workflow/SKILL.md" }, { "dependencies": [], "evidence": [ { "kind": "skill-manifest", - "path": "plugins/python-skills/skills/uv-pytest-unit-testing/SKILL.md" + "path": "plugins/python-skills/skills/python-upgrade-workflow/SKILL.md" } ], "kind": "codex-skill", - "name": "skill:python-skills/uv-pytest-unit-testing", - "path": "plugins/python-skills/skills/uv-pytest-unit-testing/SKILL.md" + "name": "skill:python-skills/python-upgrade-workflow", + "path": "plugins/python-skills/skills/python-upgrade-workflow/SKILL.md" }, { "dependencies": [], @@ -8558,6 +8938,18 @@ "name": "skill:server-side-jvm/build-java-service", "path": "plugins/server-side-jvm/skills/build-java-service/SKILL.md" }, + { + "dependencies": [], + "evidence": [ + { + "kind": "skill-manifest", + "path": "plugins/server-side-jvm/skills/build-jvm-agent-service/SKILL.md" + } + ], + "kind": "codex-skill", + "name": "skill:server-side-jvm/build-jvm-agent-service", + "path": "plugins/server-side-jvm/skills/build-jvm-agent-service/SKILL.md" + }, { "dependencies": [], "evidence": [ diff --git a/docs/maintainers/hermes-compatibility.md b/docs/maintainers/hermes-compatibility.md index 56a978879..6f1fa7fb8 100644 --- a/docs/maintainers/hermes-compatibility.md +++ b/docs/maintainers/hermes-compatibility.md @@ -57,6 +57,10 @@ Socket tap. The curated set is: - `evaluate-jailbreak-resilience` - `evaluate-tool-calling-model` - `benchmark-model-runtime` +- `build-python-agent-service` +- `fastapi-service-workflow` +- `fastmcp-service-workflow` +- `python-testing-workflow` ```bash hermes skills tap add gaelic-ghost/socket @@ -112,6 +116,11 @@ deployment routing workflow is also portable guidance: it routes Azure work to Microsoft's official Azure Skills plugin but does not claim that Azure MCP is automatically installed or configured in Hermes. +The exported Python workflows are portable guidance. They guide `uv`-managed +agent services, FastAPI services, FastMCP services, and tests while relying on +operator-installed Python tooling and project dependencies. They package no +MCP server, credentials, hook, app, or native Hermes runtime surface. + The exported macOS platform-security workflows are portable instruction contracts. Public app permission, sandbox file-access, and entitlement diagnosis remain in Apple Dev Skills; exact-build private-control research remains in Reverse Engineering Skills; defensive host investigation remains in Cybersecurity Skills. Hermes does not receive a TCC database tool, permission grant service, privileged helper, protection bypass, or native runtime plugin from this work. ## Maintainer Workflow diff --git a/docs/maintainers/python-skills-plugin-plan.md b/docs/maintainers/python-skills-plugin-plan.md index 75ccb9b8b..56ea03758 100644 --- a/docs/maintainers/python-skills-plugin-plan.md +++ b/docs/maintainers/python-skills-plugin-plan.md @@ -74,6 +74,11 @@ When a skill relies on documentation, translate the relevant rule into practical ## Current Skill Inventory +The shipped inventory has fifteen skills. The original expansion plan below +predates the later local-first agent-service addition, so this list is the +current source of truth for the audit rather than the older twelve-skill +summary in generated architecture metadata. + ### `python-skills:bootstrap-uv-python-workspace` Keep this as the shared `uv` scaffolding basis. @@ -98,11 +103,38 @@ Keep this as the existing integration bridge. It should continue to cover mounted FastMCP apps, FastAPI-derived MCP surfaces, combined app shapes, lifespan boundaries, and promotion from generated MCP surfaces to curated MCP tools and resources. -### `python-skills:uv-pytest-unit-testing` +### `python-skills:build-python-agent-service` + +Keep this as the local-first Python agent-service implementation workflow. + +It owns framework selection, exact-model capability gates, typed tool and +result contracts, evaluation fixtures, and the draft-to-approved-write +promotion boundary. It is intentionally not a generic FastAPI/FastMCP service +maintenance skill, a local-model benchmark, or a multi-agent framework survey. + +### `python-skills:fastapi-service-workflow` + +Own ongoing FastAPI service work: route and dependency composition, typed +settings, lifespan, async and integration testing, OpenAPI review, and +deployment-readiness handoff. Keep package, CI, tooling, and FastMCP concerns +with their existing owners. -Keep this for now as the tested pytest setup and execution surface. +### `python-skills:fastmcp-service-workflow` -Consider renaming or replacing it with `python-testing-workflow` only in a cleanup slice that broadens the skill to cover test selection, failure explanation, coverage, async tests, integration tests, and CI parity. Do not keep both names as long-term duplicates. +Own ongoing FastMCP server work: curated tools, resources, and prompts; +transport and lifespan behavior; authorization; client tests; generated-surface +review; and version-aware upgrade diagnostics. It is not a bundled FastMCP +documentation server or a generic deployment workflow. + +### `python-skills:python-testing-workflow` + +This replaces the earlier `uv-pytest-unit-testing` skill as the tested pytest +setup and execution surface. + +It owns test selection, fixtures, parametrization, async tests, integration +boundaries, coverage when requested, workspace targeting, failure triage, and +local-to-CI parity. The former name has no compatibility shim or duplicate +surface. ## Proposed Skill Inventory @@ -246,9 +278,9 @@ The second slice should cover repeated project operations that become more valua - [x] Add `python-skills:python-ci-workflow`. - [x] Add `python-skills:python-upgrade-workflow`. -- [x] Decide whether to broaden `uv-pytest-unit-testing` into `python-testing-workflow`; keep `uv-pytest-unit-testing` for this release so existing prompts and routing remain compatible. -- [ ] Decide whether ongoing FastAPI service maintenance needs a dedicated `fastapi-service-workflow`. -- [ ] Decide whether ongoing FastMCP server maintenance needs a dedicated `fastmcp-service-workflow`. +- [x] Replace `uv-pytest-unit-testing` with `python-testing-workflow` in one cleanup pass, retaining the tested scripts under the replacement skill. +- [x] Add `fastapi-service-workflow` for ongoing FastAPI service maintenance. +- [x] Add `fastmcp-service-workflow` for ongoing FastMCP server maintenance. - [x] Add install testing with a temporary `CODEX_HOME` if the exported skill surface or plugin metadata changes enough to need plugin-install verification. ## Deferred Scope @@ -268,15 +300,20 @@ After the first two slices prove useful, consider deeper specialized workflows: ### Testing Skill Name -Decision for now: keep `uv-pytest-unit-testing`. +Decision: replace the narrow unit-testing name with +`python-testing-workflow`. -A future cleanup can rename or replace it with `python-testing-workflow` when the scope grows beyond unit-test setup and `uv`-targeted pytest execution. If that cleanup happens, remove the old duplicate skill path in the same pass unless Gale explicitly approves a compatibility period. +The replacement covers the broader testing workflow and retains the useful +setup and package-targeting scripts. The old directory, profile paths, routing, +and discovery surface were removed in the same pass. ### Service Workflow Timing -Decision for the first slice: defer ongoing FastAPI and FastMCP service workflows. +Decision: add separate FastAPI and FastMCP service-maintenance workflows. -The existing bootstrap and integration skills already cover new service creation and combined FastAPI/FastMCP architecture. Add service-maintenance workflows only after the general `build-python-project` and `diagnose-python-project` skills prove where specialized service guidance should branch. +The bootstrap and integration skills remain focused on new service creation and +combined architecture. The dedicated maintenance workflows own existing service +behavior without absorbing package, CI, testing, tooling, or upgrade work. ### Script Depth @@ -290,6 +327,133 @@ Decision for this expansion: treat the full first implementation slice as a like The validator repair alone is a maintenance fix. Adding the new skill inventory is user-facing plugin capability and should likely publish as a minor release when the branch is ready. +## Follow-Up Audit: 2026-07-29 + +### Audit Result + +The plugin has a coherent general Python path now: choose a shape, bootstrap +it, build it, diagnose failures, test it, align tooling, validate packaging, +maintain CI, and plan upgrades. The next pass should be a focused cleanup and +service-maintenance expansion, not another broad scaffold expansion. + +The existing bootstrap skills remain distinct user-facing entry points: + +- `bootstrap-uv-python-workspace` owns generic package or service scaffolds. +- `bootstrap-python-service` owns FastAPI-first scaffolds. +- `bootstrap-python-mcp-service` owns FastMCP-first scaffolds. + +Do not merge or rename those three installed skill names. They express three +different starting intents and already share their actual scaffold mechanics. +Instead, consolidate their repeated prose, validation vocabulary, configuration +policy, and handoff matrix through shared references or a small common +bootstrap-contract asset. That preserves clear discovery without maintaining +three copies of the same policy. + +### Immediate Contract Repairs + +Complete these in one small maintenance slice before adding a new workflow: + +- [x] Correct the maintainer inventory to include + `build-python-agent-service`, then refresh the root architecture model in a + dedicated cross-plugin architecture pass. Do not hand-edit only the Python + entries: the current architecture audit reports stale targets in other + plugins too. +- [x] Remove the packaged dependency claim for `fastmcp_docs`, or add a + deliberately approved bundled MCP declaration plus its required Hermes + translation. The current plugin has two skills that require that server in + their metadata, but it does not ship the corresponding `.mcp.json` source. + The preferred narrow repair is to say “use `fastmcp_docs` when the host has + configured it; otherwise use the official FastMCP documentation,” and make + that dependency optional in the skill metadata. +- [x] Update `python-ci-workflow` to distinguish local development checks from + reproducible locked CI. For a repository that commits `uv.lock`, the default + CI example should use `uv sync --locked --all-extras --dev` only when those + extras and development groups are part of the tested contract; it should not + imply that every project needs all extras. +- [x] Add a concrete isolated wheel and sdist smoke-check recipe to + `python-package-workflow`, while keeping publication explicitly outside the + workflow. The current prose asks for a temporary consumer but leaves the + most important artifact-install proof underspecified. +- [x] Make all agent-service Python execution examples `uv`-based and remove + the unused unrestricted `Bash(python:*)` tool allowance from + `build-python-agent-service` unless a tested workflow truly needs it. + +### Consolidation Slice + +Create one shared bootstrap contract reference used by all three bootstrap +skills. It should own only the common policy: + +- `uv` command and dependency-group vocabulary; +- safe configuration defaults, secret boundaries, and typed settings; +- `pytest`, Ruff, mypy, and optional formatting-check command selection; +- project versus workspace decision and handoff rules; +- generated-artifact, git-initialization, and temporary-scaffold cleanup + boundaries. + +Each existing skill should retain only its special behavior: generic profile +selection, FastAPI overlay, or FastMCP overlay and API-mapping review. This is +a durable documentation building block, not a runtime abstraction or another +scaffold layer. + +### Next New Workflows + +Prioritize these two workflows after the contract repairs. They answer the two +open decisions from the original expansion plan and cover real work that the +current bootstrap and integration skills intentionally stop before. + +1. `fastapi-service-workflow` + - Own existing-service route composition, typed settings and dependency + overrides, lifespan, async and integration testing, OpenAPI boundary + review, deployment-readiness handoff, and service-specific diagnostics. + - Hand package, CI, general tooling, and FastMCP work back to their current + owners instead of duplicating them. +2. `fastmcp-service-workflow` + - Own existing-server transport and lifespan behavior, tool/resource/prompt + curation, authorization and input boundaries, client integration tests, + generated-surface review, and upgrade diagnostics. + - Pin implementation decisions to the installed FastMCP version and its + release documentation; the public FastMCP docs track `main` and can + describe unreleased behavior. + +### Testing Workflow Decision + +Replace `uv-pytest-unit-testing` with `python-testing-workflow` in one +deliberate cleanup release. The new skill should cover test selection, +fixtures, parametrization, async tests, integration boundaries, coverage when +requested, workspace-member targeting, failure triage, and local-to-CI parity. +Remove the old skill in that same pass and update every routing, prompt, +Hermes-export, architecture, and compatibility surface. Do not keep two +overlapping testing skills or add a compatibility shim unless Gale explicitly +approves a temporary migration window. + +### Deliberately Deferred Expansions + +These are useful only after evidence of repeated demand; they should not be +folded into the general implementation skill: + +- a CLI workflow for Typer or Click; +- a data and notebook workflow, preferably including reproducibility and + environment/kernel boundaries; +- a Django workflow; +- a background-job and task-queue workflow; +- a persistence workflow for SQLAlchemy and migration ownership; +- publishing automation, which remains an explicit release decision rather + than a normal package-validation feature. + +### Definition Of Done For The Follow-Up + +- [x] Every shipped Python skill appears in the child plan, plugin discovery + metadata, portable export decision, and regenerated architecture inventory. +- [x] Each declared MCP dependency is packaged and translated, explicitly + host-provided, or removed. +- [x] Bootstrap policies have one shared source while each entry point keeps a + narrow, distinct purpose. +- [x] CI guidance demonstrates both fast local iteration and locked, + reproducible verification without overgeneralizing either command. +- [x] FastAPI and FastMCP maintenance each have a clear owning workflow. +- [x] The renamed testing workflow replaces, rather than shadows, the current + unit-testing skill. + ## Definition Of Done The expansion is ready when: diff --git a/plugins/python-skills/.codex-plugin/plugin.json b/plugins/python-skills/.codex-plugin/plugin.json index 64c9e4659..be1537bd2 100644 --- a/plugins/python-skills/.codex-plugin/plugin.json +++ b/plugins/python-skills/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "python-skills", "version": "9.25.0", - "description": "Bundled Python-focused Codex skills for uv bootstrapping, project implementation, diagnostics, packaging, tooling, CI, upgrades, FastAPI, FastMCP, and pytest workflows.", + "description": "Bundled Python-focused Codex skills for uv bootstrapping, project implementation, diagnostics, packaging, tooling, CI, upgrades, FastAPI service maintenance, FastMCP service maintenance, and testing workflows.", "author": { "name": "Gale", "email": "mail@galewilliams.com", @@ -29,7 +29,7 @@ "interface": { "displayName": "Python Skills", "shortDescription": "Python project, uv, FastAPI, FastMCP, pytest, package, tooling, CI, and upgrade workflows for Codex.", - "longDescription": "Bundle reusable Codex skills for choosing Python project shapes, building uv-managed Python projects, diagnosing Python failures, validating package surfaces, aligning tooling, maintaining CI, planning upgrades, bootstrapping FastAPI and FastMCP services, integrating FastAPI/FastMCP apps, and setting up pytest workflows.", + "longDescription": "Bundle reusable Codex skills for choosing Python project shapes, building uv-managed Python projects, diagnosing Python failures, validating package surfaces, aligning tooling, maintaining CI, planning upgrades, bootstrapping and maintaining FastAPI and FastMCP services, integrating FastAPI/FastMCP apps, and testing Python projects.", "developerName": "gaelic-ghost", "category": "Developer Tools", "capabilities": [ @@ -46,7 +46,9 @@ "Align this Python repo's uv, Ruff, mypy, pytest, dependency-group, and validation workflow.", "Align this Python repo's CI with local uv validation commands.", "Plan this Python dependency, framework, lockfile, or tooling upgrade with staged validation.", - "Set up pytest defaults for this uv workspace and show the right package-targeted test commands.", + "Set up, run, or diagnose pytest for this uv workspace with explicit package targeting.", + "Maintain this FastAPI service's routes, typed settings, lifespan, OpenAPI contract, and tests.", + "Maintain this FastMCP server's curated tools, resources, prompts, transport, authorization, and client tests.", "Add a FastMCP surface to an existing FastAPI project and choose the right combined-app pattern." ], "brandColor": "#0F766E", diff --git a/plugins/python-skills/shared/bootstrap-contract.md b/plugins/python-skills/shared/bootstrap-contract.md new file mode 100644 index 000000000..06144aa92 --- /dev/null +++ b/plugins/python-skills/shared/bootstrap-contract.md @@ -0,0 +1,59 @@ +# Shared Python Bootstrap Contract + +Use this contract for every generated Python project, FastAPI service, and +FastMCP service. It owns the policy common to the three bootstrap entry points; +framework-specific overlays remain with their own skills. + +## Command And Dependency Policy + +- Use `uv` for project creation, dependency changes, locking, syncing, and + command execution. +- Keep runtime imports in `[project].dependencies`, optional user-facing + features in `[project.optional-dependencies]`, and maintainer tooling in + `[dependency-groups]`. +- Install and run `pytest`, Ruff, and mypy through `uv`; do not rely on a + globally installed Python tool. +- Use a single project for one package or service. Use a workspace only when + multiple members have a real local package relationship. + +## Configuration And Secret Policy + +- Commit only safe, non-secret defaults in `.env` when the selected scaffold + uses environment-backed settings. +- Keep machine-local or secret values in ignored `.env.local` or the target + deployment's secret store. +- Keep typed configuration in a dedicated settings module. Tests override + environment values or a settings dependency rather than modifying committed + defaults. + +## Validation And Cleanup + +Run the scaffold's emitted commands first, then use the narrowest configured +checks for the changed member or project: + +```bash +uv run pytest +uv run ruff check . +uv run mypy . +``` + +Run `uv run ruff format --check .` only when the generated or target project +enforces formatting. For a workspace, target the intended member with +`uv run --package ...` when a full workspace sweep is unnecessary. + +Do not overwrite a non-empty target or existing `pyproject.toml` without the +entrypoint's explicit force flag. Initialize git only when requested by the +entrypoint defaults, and remove temporary scaffold output only after reporting +the validation result. + +## Handoff Matrix + +| Need | Owning skill | +| --- | --- | +| Generic package or service scaffold | `bootstrap-uv-python-workspace` | +| New FastAPI service | `bootstrap-python-service` | +| New FastMCP server | `bootstrap-python-mcp-service` | +| Existing FastAPI and FastMCP integration | `integrate-fastapi-fastmcp` | +| Existing-project implementation | `build-python-project` | +| Test setup or testing workflow | `python-testing-workflow` | +| Tooling, package, CI, or upgrade maintenance | The corresponding `python-*-workflow` skill | diff --git a/plugins/python-skills/skills/bootstrap-python-mcp-service/SKILL.md b/plugins/python-skills/skills/bootstrap-python-mcp-service/SKILL.md index de6f84847..473a8bb77 100644 --- a/plugins/python-skills/skills/bootstrap-python-mcp-service/SKILL.md +++ b/plugins/python-skills/skills/bootstrap-python-mcp-service/SKILL.md @@ -2,7 +2,7 @@ name: bootstrap-python-mcp-service description: Bootstrap Python MCP server projects and workspaces on macOS using uv and FastMCP with consistent defaults. Use when creating a new MCP server from scratch, scaffolding a single uv MCP project, scaffolding a uv workspace with package/service members, customizing scaffold defaults through layered YAML profiles, initializing pytest+ruff+mypy defaults, creating README.md, initializing git, running initial validation checks, or starting from OpenAPI/FastAPI with MCP mapping guidance. license: Apache-2.0 -compatibility: Designed for Codex and compatible Agent Skills clients on macOS with uv, git, FastMCP-oriented Python workflows, and access to the fastmcp_docs MCP server for live framework guidance. +compatibility: Designed for Codex and compatible Agent Skills clients on macOS with uv, git, and FastMCP-oriented Python workflows. Use a host-provided FastMCP documentation tool when available; otherwise use the official FastMCP documentation. metadata: owner: gaelic-ghost repo: python-skills @@ -16,6 +16,10 @@ allowed-tools: Bash(uv:*) Bash(git:*) Read Create FastMCP starter layouts using one direct shell entrypoint backed by the shared `bootstrap-uv-python-workspace` scaffolding scripts plus deterministic MCP overlay logic. +Read [`shared/bootstrap-contract.md`](../../shared/bootstrap-contract.md) +before changing shared scaffold policy. It owns shared command, configuration, +validation, cleanup, and handoff rules. + ## When To Use - Use this skill for new FastMCP server scaffolds. @@ -34,16 +38,9 @@ Create FastMCP starter layouts using one direct shell entrypoint backed by the s scripts/init_fastmcp_service.sh --name --mode ``` 3. Let the script delegate to the shared `bootstrap-uv-python-workspace` scaffolding layer, then apply the FastMCP overlay. -4. Accept the built-in validation path: - - `uv run pytest` - - `uv run ruff check .` - - `uv run mypy .` -5. Confirm the generated project includes: - - a committed `.env` for safe defaults - - an ignored `.env.local` for machine-local or secret overrides - - typed configuration via `pydantic-settings` -6. If the task starts from an existing API, optionally generate a mapping report with `uv run scripts/assess_api_for_mcp.py ...`. -7. Return the generated path plus the exact next-step commands emitted by the script. +4. Apply the shared bootstrap contract for validation and configuration. +5. If the task starts from an existing API, optionally generate a mapping report with `uv run scripts/assess_api_for_mcp.py ...`. +6. Return the generated path plus the exact next-step commands emitted by the script. ## Commands @@ -110,8 +107,6 @@ uv run scripts/assess_api_for_mcp.py --fastapi app.main:app --out ./mcp_mapping_ - mode: `project` - Python version: `3.13` -- quality tooling: `pytest`, `ruff`, `mypy` -- config baseline: committed `.env`, ignored `.env.local`, and `pydantic-settings` - workspace default members: `core-lib,api-service` - workspace default profiles: first member `package`, remaining members `service` @@ -137,9 +132,12 @@ When starting from OpenAPI or FastAPI, bootstrap first, then map endpoints to MC 3. Recommend RouteMaps/Transforms only when they improve usability. 4. Keep bootstrap deterministic; defer heavy custom mapping unless requested. -## FastMCP Docs Lookup +## FastMCP Documentation Lookup -Use the `fastmcp_docs` MCP server for up-to-date framework details. +Use a host-provided `fastmcp_docs` MCP server when it is available. This plugin +does not package that server. Otherwise, use the official +[FastMCP documentation](https://gofastmcp.com/getting-started/welcome) and +confirm the installed FastMCP version before copying syntax-sensitive examples. Suggested queries: @@ -151,18 +149,13 @@ Suggested queries: ## Guardrails -- Refuse non-empty target directories unless `--force` is set. +- Apply the shared bootstrap-contract guardrails. - Require at least one service profile member in workspace mode. -- Require `uv` and `git` unless git initialization was explicitly disabled. -- Fail when workspace-only options are used in project mode. -- Fail when `--initial-commit` is combined with `--no-git-init`. ## Fallbacks and Handoffs - The preferred path is always `scripts/init_fastmcp_service.sh`. -- Use `bootstrap-python-service` when the user wants FastAPI-only output. -- Use `bootstrap-uv-python-workspace` directly only when FastMCP-specific behavior is not wanted. -- Recommend `integrate-fastapi-fastmcp` when the user needs to fold this FastMCP output into an existing FastAPI app, mount an MCP server into FastAPI, or promote generated FastAPI-derived MCP output into a curated combined architecture. +- Use the shared bootstrap-contract handoff matrix. ## Automation Suitability @@ -253,6 +246,7 @@ Run only commands needed for this flow, then return STATUS, exact command transc ## References +- `../../shared/bootstrap-contract.md` - `references/mcp-mapping-guidelines.md` - `references/fastmcp-docs-lookup.md` - `references/customization.md` diff --git a/plugins/python-skills/skills/bootstrap-python-mcp-service/agents/openai.yaml b/plugins/python-skills/skills/bootstrap-python-mcp-service/agents/openai.yaml index 99e9efe67..20962280c 100644 --- a/plugins/python-skills/skills/bootstrap-python-mcp-service/agents/openai.yaml +++ b/plugins/python-skills/skills/bootstrap-python-mcp-service/agents/openai.yaml @@ -4,11 +4,5 @@ interface: brand_color: "#1D4ED8" default_prompt: "Use $bootstrap-python-mcp-service to create a uv FastMCP project or workspace, generate committed .env defaults plus ignored .env.local overrides, add pydantic-settings configuration, run the canonical shell entrypoint, and optionally generate an OpenAPI or FastAPI mapping report with uv run." -dependencies: - tools: - - type: "mcp" - value: "fastmcp_docs" - description: "FastMCP documentation search" - policy: allow_implicit_invocation: true diff --git a/plugins/python-skills/skills/bootstrap-python-mcp-service/references/fastmcp-docs-lookup.md b/plugins/python-skills/skills/bootstrap-python-mcp-service/references/fastmcp-docs-lookup.md index a461cf5fd..3fdbaa03c 100644 --- a/plugins/python-skills/skills/bootstrap-python-mcp-service/references/fastmcp-docs-lookup.md +++ b/plugins/python-skills/skills/bootstrap-python-mcp-service/references/fastmcp-docs-lookup.md @@ -1,6 +1,10 @@ # FastMCP Docs Lookup Patterns -Use these search prompts with the `fastmcp_docs` MCP server for current implementation details. +Use these search prompts with a host-provided `fastmcp_docs` MCP server when +one is available. The Python Skills plugin does not package that server. When +it is unavailable, search the official [FastMCP documentation](https://gofastmcp.com/getting-started/welcome) +instead, then compare the result against the installed FastMCP version before +using syntax-sensitive examples. ## General bootstrapping diff --git a/plugins/python-skills/skills/bootstrap-python-service/SKILL.md b/plugins/python-skills/skills/bootstrap-python-service/SKILL.md index 779d1f5c9..25bdd70d4 100644 --- a/plugins/python-skills/skills/bootstrap-python-service/SKILL.md +++ b/plugins/python-skills/skills/bootstrap-python-service/SKILL.md @@ -16,6 +16,10 @@ allowed-tools: Bash(uv:*) Bash(git:*) Read Create production-oriented FastAPI starter layouts using one direct shell entrypoint backed by the shared `bootstrap-uv-python-workspace` scaffolding scripts. +Read [`shared/bootstrap-contract.md`](../../shared/bootstrap-contract.md) +before changing shared scaffold policy. It owns the shared command, +configuration, validation, cleanup, and handoff rules. + ## When To Use - Use this skill for new FastAPI service scaffolds. @@ -34,15 +38,8 @@ Create production-oriented FastAPI starter layouts using one direct shell entryp scripts/init_python_service.sh --name --mode ``` 3. Let the script delegate to the shared `bootstrap-uv-python-workspace` scaffolding layer. -4. Accept the built-in validation path: - - `uv run pytest` - - `uv run ruff check .` - - `uv run mypy .` -5. Confirm the generated project includes: - - a committed `.env` for safe defaults - - an ignored `.env.local` for machine-local or secret overrides - - typed configuration via `pydantic-settings` -6. Return the generated path plus the exact next-step run and check commands emitted by the script. +4. Apply the shared bootstrap contract for validation and configuration. +5. Return the generated path plus the exact next-step run and check commands emitted by the script. ## Commands @@ -102,17 +99,12 @@ scripts/init_python_service.sh --name my-service --initial-commit - mode: `project` - Python version: `3.13` -- quality tooling: `pytest`, `ruff`, `mypy` -- config baseline: committed `.env`, ignored `.env.local`, and `pydantic-settings` - workspace default members: `core-lib,api-service` - workspace default profiles: first member `package`, remaining members `service` ## Guardrails -- Refuse non-empty target directories unless `--force` is set. -- Require `uv` and `git` unless git initialization was explicitly disabled. -- Fail when workspace-only options are used in project mode. -- Fail when `--initial-commit` is combined with `--no-git-init`. +- Apply the shared bootstrap-contract guardrails. ## FastAPI Guidance @@ -126,14 +118,13 @@ uv run fastapi dev app/main.py uv run fastapi run app/main.py ``` -Generated FastAPI scaffolds should use `pydantic-settings` with `.env` plus `.env.local`, following the documented FastAPI settings pattern with cached settings loading. +Generated FastAPI scaffolds should use the shared configuration policy and the +documented FastAPI settings pattern with cached settings loading. ## Fallbacks and Handoffs - The preferred path is always `scripts/init_python_service.sh`. -- Use `bootstrap-uv-python-workspace` directly only when FastAPI-specific behavior is not wanted. -- Recommend `bootstrap-python-mcp-service` instead when the user wants a FastMCP server rather than an HTTP API service. -- Recommend `integrate-fastapi-fastmcp` when the user wants an existing or planned FastAPI project to host, generate, or coexist with a FastMCP surface. +- Use the shared bootstrap-contract handoff matrix. ## Automation Suitability @@ -227,6 +218,7 @@ Return STATUS, generated path, exact command transcript, and minimal remediation ## References +- `../../shared/bootstrap-contract.md` - `references/conventions.md` - `references/customization.md` - `references/interactive-customization.md` diff --git a/plugins/python-skills/skills/bootstrap-uv-python-workspace/SKILL.md b/plugins/python-skills/skills/bootstrap-uv-python-workspace/SKILL.md index fb9cca494..7bd54cbb4 100644 --- a/plugins/python-skills/skills/bootstrap-uv-python-workspace/SKILL.md +++ b/plugins/python-skills/skills/bootstrap-uv-python-workspace/SKILL.md @@ -17,6 +17,10 @@ allowed-tools: Bash(uv:*) Bash(git:*) Read Create repeatable `uv`-based scaffolds for both single projects and workspaces. Use this skill as the shared scaffolding basis for other Python bootstrap skills that need consistent `uv` project and workspace defaults. +Read [`shared/bootstrap-contract.md`](../../shared/bootstrap-contract.md) +before changing defaults or validating generated output. It owns shared command, +configuration, validation, cleanup, and handoff policy. + ## When To Use - Use this skill for generic `uv` project or workspace creation. @@ -32,15 +36,8 @@ Use this skill as the shared scaffolding basis for other Python bootstrap skills - `package` - `service` 3. Run the selected script with explicit `--name` and optional `--path`, `--python`, `--force`, `--initial-commit`, and `--no-git-init`. -4. Accept the built-in validation path: - - `uv run pytest` - - `uv run ruff check .` - - `uv run mypy .` -5. Confirm the generated output includes: - - a committed `.env` for safe defaults - - an ignored `.env.local` for machine-local or secret overrides - - typed configuration via `pydantic-settings` -6. Return the generated path plus the exact next-step commands emitted by the script. +4. Apply the shared bootstrap contract for validation and configuration. +5. Return the generated path plus the exact next-step commands emitted by the script. ## Commands @@ -73,8 +70,6 @@ scripts/init_uv_python_project.sh --name my-service --profile service --initial- ## Defaults - Python version: `3.13` (override with `--python`). -- Quality tooling: `pytest`, `ruff`, `mypy`. -- Config baseline: committed `.env`, ignored `.env.local`, and `pydantic-settings`. - Git initialization: enabled by default (disable via `--no-git-init`). - Workspace defaults: - Members: `core-lib,api-service` @@ -97,16 +92,12 @@ scripts/init_uv_python_project.sh --name my-service --profile service --initial- ## Guardrails - Refuse non-empty target directories unless `--force` is set. -- Refuse to overwrite an existing `pyproject.toml`. -- Require `uv` and `git` when git initialization is enabled. -- Exit non-zero with actionable error text for invalid arguments or missing prerequisites. +- Apply the shared bootstrap-contract guardrails. ## Fallbacks and Handoffs - Preferred paths are `scripts/init_uv_python_project.sh` and `scripts/init_uv_python_workspace.sh`. -- Recommend `bootstrap-python-service` when the user wants FastAPI-first scaffolding. -- Recommend `bootstrap-python-mcp-service` when the user wants FastMCP-first scaffolding. -- Recommend `integrate-fastapi-fastmcp` when the user already has one surface and needs integration guidance for the other inside the same `uv` project or workspace. +- Use the shared bootstrap-contract handoff matrix. ## Automation Suitability @@ -199,6 +190,7 @@ Return STATUS, exact commands, and concise results only. If failures occur, prov ## References +- `../../shared/bootstrap-contract.md` - `references/uv-command-recipes.md` - `references/customization.md` diff --git a/plugins/python-skills/skills/build-python-agent-service/SKILL.md b/plugins/python-skills/skills/build-python-agent-service/SKILL.md index 62d6efe2a..5f8b575ee 100644 --- a/plugins/python-skills/skills/build-python-agent-service/SKILL.md +++ b/plugins/python-skills/skills/build-python-agent-service/SKILL.md @@ -7,7 +7,7 @@ metadata: owner: gaelic-ghost repo: python-skills category: python-agent-service -allowed-tools: Read Bash(rg:*) Bash(git:*) Bash(uv:*) Bash(python:*) +allowed-tools: Read Bash(rg:*) Bash(git:*) Bash(uv:*) --- # Build Python Agent Service diff --git a/plugins/python-skills/skills/choose-python-project-shape/SKILL.md b/plugins/python-skills/skills/choose-python-project-shape/SKILL.md index 903c499c6..e0181d085 100644 --- a/plugins/python-skills/skills/choose-python-project-shape/SKILL.md +++ b/plugins/python-skills/skills/choose-python-project-shape/SKILL.md @@ -74,7 +74,7 @@ Translate any documentation rule into the concrete repository decision it change 5. Choose the next skill: - scaffold: `bootstrap-uv-python-workspace`, `bootstrap-python-service`, or `bootstrap-python-mcp-service` - implementation: `build-python-project` - - test work: `uv-pytest-unit-testing` + - test work: `python-testing-workflow` - FastAPI/FastMCP integration: `integrate-fastapi-fastmcp` - local-first agent service: `build-python-agent-service` - diagnosis: `diagnose-python-project` diff --git a/plugins/python-skills/skills/fastapi-service-workflow/SKILL.md b/plugins/python-skills/skills/fastapi-service-workflow/SKILL.md new file mode 100644 index 000000000..1210141da --- /dev/null +++ b/plugins/python-skills/skills/fastapi-service-workflow/SKILL.md @@ -0,0 +1,89 @@ +--- +name: fastapi-service-workflow +description: Maintain existing uv-managed FastAPI services, including route and dependency composition, typed settings, lifespan, async and integration testing, OpenAPI review, deployment-readiness handoff, and service-specific diagnostics. +license: Apache-2.0 +compatibility: Designed for Codex and compatible Agent Skills clients maintaining FastAPI services on macOS with uv, typed configuration, async Python, and the repository's existing deployment tools. +metadata: + owner: gaelic-ghost + repo: python-skills + category: python-fastapi +allowed-tools: Read Bash(rg:*) Bash(git:*) Bash(uv:*) +--- + +# FastAPI Service Workflow + +## Purpose + +Maintain an existing FastAPI service without turning routing, application +lifecycle, domain logic, deployment, and MCP integration into one layer. Keep +HTTP adapters thin around typed domain behavior and make startup, shutdown, +configuration, and public API changes explicit. + +## Workflow + +1. Inspect `pyproject.toml`, app entrypoint, routers, dependencies, settings, + lifespan, tests, OpenAPI output, CI, and deployment configuration. +2. Classify the requested change as route composition, request/response model, + dependency, settings, lifecycle, async boundary, public OpenAPI contract, or + deployment-readiness work. +3. Keep route handlers focused on HTTP translation. Put reusable behavior in + domain modules or existing service boundaries rather than duplicating it + across routes, CLI commands, or MCP tools. +4. Keep settings typed and injectable. Store safe defaults separately from + machine-local or deployment secrets; use dependency overrides in tests. +5. Use one lifespan contract for resources such as pools, clients, queues, and + background workers. Combine lifespans deliberately when mounting another + ASGI application instead of silently replacing startup or shutdown work. +6. Review the OpenAPI effect of public routes, models, status codes, operation + IDs, security requirements, and deprecations. Treat incompatible changes as + an API compatibility decision. +7. Run focused HTTP and async tests, then the repository's configured checks: + ```bash + uv run pytest + uv run ruff check . + uv run mypy . + ``` +8. Report deployment readiness separately: configuration source, migrations, + health endpoint, logs, timeouts, workers, and external dependencies. Do not + deploy unless the user asks for that operation. + +## Testing And Diagnostics + +Use dependency overrides for paid, privileged, or nondeterministic services and +clear them after each test. Use an async client for async behavior, and make +lifespan execution explicit when tests depend on startup resources. + +Diagnose service failures in this order: import or app factory, settings, +lifespan, route/dependency resolution, response validation, async boundary, +then external integration. Hand generic lockfile, package, CI, or tool failures +to their existing Python workflows. + +## Handoffs + +- New service scaffolding: `bootstrap-python-service`. +- Generic implementation and package structure: `build-python-project`. +- FastAPI plus FastMCP in one codebase: `integrate-fastapi-fastmcp`. +- MCP service maintenance: `fastmcp-service-workflow`. +- Package, CI, testing, tooling, and upgrade work: their corresponding Python + workflows. + +## Output Shape + +Return the service boundary changed, HTTP/OpenAPI impact, settings and +lifespan effect, tests and commands run, deployment-readiness evidence, and +residual risk. + +## Guardrails + +- Do not add a repository, manager, or service wrapper when a route can call an + existing typed domain boundary directly. +- Do not run a service, migration, external write, or deployment merely to + validate static guidance without user approval. +- Do not change public OpenAPI behavior silently. + +## References + +- [FastAPI lifespan events](https://fastapi.tiangolo.com/advanced/events/) +- [FastAPI settings](https://fastapi.tiangolo.com/advanced/settings/) +- [FastAPI dependency overrides](https://fastapi.tiangolo.com/advanced/testing-dependencies/) +- [FastAPI async tests](https://fastapi.tiangolo.com/advanced/async-tests/) diff --git a/plugins/python-skills/skills/fastapi-service-workflow/agents/openai.yaml b/plugins/python-skills/skills/fastapi-service-workflow/agents/openai.yaml new file mode 100644 index 000000000..7abdbf506 --- /dev/null +++ b/plugins/python-skills/skills/fastapi-service-workflow/agents/openai.yaml @@ -0,0 +1,8 @@ +interface: + display_name: "FastAPI Service Workflow" + short_description: "Maintain FastAPI routes, settings, lifespan, OpenAPI, and service tests." + brand_color: "#0F766E" + default_prompt: "Use $fastapi-service-workflow to inspect this existing FastAPI service, preserve its typed settings and lifespan contract, implement the requested route or dependency change, review the OpenAPI impact, and run focused uv validation." + +policy: + allow_implicit_invocation: true diff --git a/plugins/python-skills/skills/fastmcp-service-workflow/SKILL.md b/plugins/python-skills/skills/fastmcp-service-workflow/SKILL.md new file mode 100644 index 000000000..7b6e91416 --- /dev/null +++ b/plugins/python-skills/skills/fastmcp-service-workflow/SKILL.md @@ -0,0 +1,82 @@ +--- +name: fastmcp-service-workflow +description: Maintain existing uv-managed FastMCP servers, including transport and lifespan behavior, tool/resource/prompt curation, authorization and input boundaries, client integration tests, generated-surface review, and upgrade diagnostics. +license: Apache-2.0 +compatibility: Designed for Codex and compatible Agent Skills clients maintaining FastMCP servers on macOS with uv, the installed FastMCP version, and the repository's existing transport and deployment tools. +metadata: + owner: gaelic-ghost + repo: python-skills + category: python-fastmcp +allowed-tools: Read Bash(rg:*) Bash(git:*) Bash(uv:*) +--- + +# FastMCP Service Workflow + +## Purpose + +Maintain a curated FastMCP server as an application surface, not a mechanical +mirror of HTTP routes. Keep tool, resource, and prompt design user-oriented; +make transport, authentication, authorization, lifespan, and side-effect +boundaries explicit. + +## Workflow + +1. Inspect the installed FastMCP version, `pyproject.toml`, server entrypoint, + component definitions, transport, lifespan, auth configuration, tests, and + deployment configuration before changing behavior. +2. Classify each public capability: + - a tool for an action or bounded computation; + - a resource or template for read-oriented data; + - a prompt for a reusable message workflow. +3. Keep implementation logic in existing typed domain boundaries. Do not expose + transport-centric route names, broad autogenerated APIs, secrets, or raw + infrastructure controls as MCP capabilities. +4. Choose transport deliberately. STDIO clients own the server process and its + environment; HTTP is the normal production transport. Make every required + configuration value explicit for the selected transport. +5. Define authorization at the component or server boundary when the HTTP + deployment needs it. Do not infer identity or permissions from a model's + request, and do not claim HTTP OAuth checks protect STDIO transport. +6. Treat `FastMCP.from_fastapi(...)` and OpenAPI imports as review inputs. + Curate names, parameter shapes, errors, and capability boundaries before + keeping generated output as a public server surface. +7. Test through an in-memory FastMCP client first, then add transport and auth + integration tests only where those are part of the deployment contract. +8. Run the repository's configured checks and report any untested transport, + authorization, or external-write boundary separately. + +## Version And Documentation Discipline + +Use the installed FastMCP version and its release notes for implementation +decisions. The public FastMCP documentation tracks `main` and can describe +unreleased behavior. Use a host-provided `fastmcp_docs` tool only when one is +already configured; this plugin does not package it. + +## Handoffs + +- New MCP scaffold: `bootstrap-python-mcp-service`. +- FastAPI/FastMCP coexistence or mounting: `integrate-fastapi-fastmcp`. +- FastAPI service maintenance: `fastapi-service-workflow`. +- Generic testing, package, CI, tooling, and upgrade work: the corresponding + Python workflows. + +## Output Shape + +Return the component and transport boundary changed, installed FastMCP version, +authorization effect, test commands and results, deployment-readiness effect, +and residual risk. + +## Guardrails + +- Do not add a generated route mirror as a long-term MCP API without curation. +- Do not expose write-capable tools without explicit authorization, input, + timeout, idempotency, and approval behavior. +- Do not run a production transport, deploy a server, or execute live writes + only to validate the skill. + +## References + +- [FastMCP client testing](https://gofastmcp.com/servers/testing) +- [FastMCP transports](https://gofastmcp.com/clients/transports) +- [FastMCP authorization](https://gofastmcp.com/servers/authorization) +- [FastMCP CLI](https://gofastmcp.com/cli/overview) diff --git a/plugins/python-skills/skills/fastmcp-service-workflow/agents/openai.yaml b/plugins/python-skills/skills/fastmcp-service-workflow/agents/openai.yaml new file mode 100644 index 000000000..da01051c8 --- /dev/null +++ b/plugins/python-skills/skills/fastmcp-service-workflow/agents/openai.yaml @@ -0,0 +1,8 @@ +interface: + display_name: "FastMCP Service Workflow" + short_description: "Maintain FastMCP components, transports, authorization, and client tests." + brand_color: "#1D4ED8" + default_prompt: "Use $fastmcp-service-workflow to inspect this existing FastMCP server and installed version, curate the requested tool, resource, or prompt change, preserve transport and authorization boundaries, and validate it with a focused uv client test." + +policy: + allow_implicit_invocation: true diff --git a/plugins/python-skills/skills/integrate-fastapi-fastmcp/SKILL.md b/plugins/python-skills/skills/integrate-fastapi-fastmcp/SKILL.md index 496d84ce4..83eafe0ba 100644 --- a/plugins/python-skills/skills/integrate-fastapi-fastmcp/SKILL.md +++ b/plugins/python-skills/skills/integrate-fastapi-fastmcp/SKILL.md @@ -2,7 +2,7 @@ name: integrate-fastapi-fastmcp description: Integrate FastAPI and FastMCP applications in existing or evolving uv-managed Python projects. Use when adding a FastMCP server to an existing FastAPI app, folding an existing FastMCP server into a FastAPI project, serving both REST and MCP interfaces from one codebase, or graduating an auto-generated FastAPI-to-FastMCP server into a curated FastMCP application. license: Apache-2.0 -compatibility: Designed for Codex and compatible Agent Skills clients on macOS with uv-managed Python projects, FastAPI and FastMCP application code, shell access for uv commands, and access to the fastmcp_docs MCP server for current framework guidance. +compatibility: Designed for Codex and compatible Agent Skills clients on macOS with uv-managed Python projects, FastAPI and FastMCP application code, and shell access for uv commands. Use a host-provided FastMCP documentation tool when available; otherwise use the official FastMCP documentation. metadata: owner: gaelic-ghost repo: python-skills @@ -152,3 +152,7 @@ When a combined FastAPI/FastMCP setup starts demanding separate service members, - `references/integration-patterns.md` - `references/official-docs.md` +Use a host-provided `fastmcp_docs` MCP server only when the host already has +one configured. This plugin does not package that server; otherwise use the +official FastMCP documentation and verify the installed FastMCP version before +adopting version-sensitive integration code. diff --git a/plugins/python-skills/skills/integrate-fastapi-fastmcp/agents/openai.yaml b/plugins/python-skills/skills/integrate-fastapi-fastmcp/agents/openai.yaml index ffbc17c37..f101e9623 100644 --- a/plugins/python-skills/skills/integrate-fastapi-fastmcp/agents/openai.yaml +++ b/plugins/python-skills/skills/integrate-fastapi-fastmcp/agents/openai.yaml @@ -4,12 +4,5 @@ interface: brand_color: "#0E7490" default_prompt: "Use $integrate-fastapi-fastmcp to choose the right FastAPI and FastMCP integration pattern for this uv-managed project, keep typed settings and shared domain logic coherent, and promote any auto-generated FastAPI-to-FastMCP surface into a curated MCP design when needed." -dependencies: - tools: - - type: "mcp" - value: "fastmcp_docs" - description: "FastMCP documentation search" - policy: allow_implicit_invocation: true - diff --git a/plugins/python-skills/skills/python-ci-workflow/SKILL.md b/plugins/python-skills/skills/python-ci-workflow/SKILL.md index 2a6baf1b9..f191b592d 100644 --- a/plugins/python-skills/skills/python-ci-workflow/SKILL.md +++ b/plugins/python-skills/skills/python-ci-workflow/SKILL.md @@ -64,9 +64,9 @@ Use repo-local files, checked-out dependency sources, Dash MCP or Dash HTTP for - one OS unless filesystem, process, path, native dependency, or user-facing CLI behavior requires cross-platform checks 6. Keep local and CI commands aligned. -## Baseline Command Order +## Local And CI Command Boundaries -Prefer a simple shape: +For local development, prefer the narrowest useful shape: ```bash uv sync --dev @@ -87,6 +87,21 @@ Add package validation only for package surfaces: uv build ``` +For reproducible CI in a repository that commits `uv.lock`, use a locked sync. +Include all extras only when the job intentionally validates every extra: + +```bash +# Typical locked CI job +uv sync --locked --dev + +# Use only when every optional feature is part of this job's contract +uv sync --locked --all-extras --dev +``` + +Do not copy `--all-extras` into application CI by default. A service with no +published extras should validate its actual runtime and development dependency +groups instead. + For workspaces, target package-specific jobs explicitly when the repo does not need a full workspace sweep: ```bash @@ -102,7 +117,8 @@ Use the repo's existing workflow style first. For new GitHub Actions workflows: - install `uv` through the official setup action or documented installer path -- use `uv sync --dev` unless the repo documents a narrower sync command +- use `uv sync --locked --dev` when the repository commits `uv.lock`; add + `--all-extras` only when the job intentionally validates all extras - cache only when it measurably helps and the cache key includes lockfile state - keep package build or publish steps separate from normal validation - avoid CI secrets unless a workflow truly needs private package sources or publishing diff --git a/plugins/python-skills/skills/python-package-workflow/SKILL.md b/plugins/python-skills/skills/python-package-workflow/SKILL.md index 646b55706..2a58e338d 100644 --- a/plugins/python-skills/skills/python-package-workflow/SKILL.md +++ b/plugins/python-skills/skills/python-package-workflow/SKILL.md @@ -88,7 +88,19 @@ Do not assume every workspace member should publish. Services, examples, interna ## Local Smoke Checks -When package behavior is public or packaging changed materially, create a temporary consumer outside the package tree and install the built artifact there. +When package behavior is public or packaging changed materially, create a +temporary consumer outside the package tree and install the built artifact +there. Verify both the wheel and sdist when the project publishes both: + +```bash +uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py +uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py +``` + +Keep `tests/smoke_test.py` deliberately small: import the public package, run +one representative public API or CLI command, and fail if required package data +is missing. Use a disposable directory instead when the repository does not +ship a smoke-test script. Keep the smoke check small: diff --git a/plugins/python-skills/skills/python-testing-workflow/SKILL.md b/plugins/python-skills/skills/python-testing-workflow/SKILL.md new file mode 100644 index 000000000..9b0857470 --- /dev/null +++ b/plugins/python-skills/skills/python-testing-workflow/SKILL.md @@ -0,0 +1,125 @@ +--- +name: python-testing-workflow +description: Set up, run, and improve Python tests in uv projects and workspaces. Use for pytest configuration, focused and package-targeted runs, fixtures, parametrization, async and integration tests, coverage, CI parity, or failure triage. +license: Apache-2.0 +compatibility: Designed for Codex and compatible Agent Skills clients on macOS with uv-managed Python projects, pytest, and shell access for the bundled setup and execution scripts. +metadata: + owner: gaelic-ghost + repo: python-skills + category: python-testing +allowed-tools: Bash(uv:*) Read +--- + +# Python Testing Workflow + +## Purpose + +Make Python tests describe behavior, run through `uv`, and give a focused +failure signal. Preserve the repository's existing test framework and markers; +use the bundled scripts only for pytest setup or repeatable package-targeted +runs. + +## Workflow + +1. Inspect `pyproject.toml`, existing tests, CI, markers, fixtures, package + layout, and workspace members before changing test configuration. +2. Choose the smallest useful test boundary: + - unit tests for pure behavior and fakeable dependencies; + - integration tests for framework, database, filesystem, network, or + process boundaries; + - a client test for public HTTP or MCP behavior; + - a package-artifact smoke test when package contents changed. +3. Run a focused check first: + ```bash + uv run pytest tests/unit + uv run pytest -k "auth and not slow" + uv run --package pytest + ``` +4. Add fixtures for reusable setup, keep their scope minimal, and use + `@pytest.mark.parametrize` for input/output matrices. +5. Use `monkeypatch`, dependency overrides, fakes, or disposable services at + the boundary rather than mutating committed configuration or calling a live + dependency during every test. +6. Use async tests only when the code under test is async. Configure the + repository's async test support explicitly and verify lifespan behavior when + the app owns startup or shutdown resources. +7. Run the relevant complete test selection, then the project's CI-equivalent + validation commands. Add coverage only when the user or repository has a + concrete coverage threshold or reporting need. + +## Setup And Execution Scripts + +For a new pytest setup or a repeatable workspace command, use the existing +scripts: + +```bash +scripts/bootstrap_pytest_uv.sh --workspace-root +scripts/bootstrap_pytest_uv.sh --workspace-root --package +scripts/run_pytest_uv.sh --workspace-root --package +scripts/run_pytest_uv.sh --workspace-root --path tests/integration -- -m integration +``` + +Use `--with-cov` only when the requested test contract needs `pytest-cov`. +Profiles use the `python-testing-workflow` name and should remain optional; +ordinary repositories should work from their checked-in `pyproject.toml` alone. + +## FastAPI And FastMCP Boundaries + +For FastAPI, override external dependencies with +`app.dependency_overrides`, reset them after the test, and use an async client +when the test itself needs async behavior. Ensure lifespan events run when the +application depends on them. + +For FastMCP, prefer an in-memory `Client(mcp)` test for deterministic server +behavior, then add transport or authorization integration tests only for the +configured deployment shape. Test listed and callable tools, readable +resources, and rendered prompts separately when each surface is public. + +## Failure Triage + +Classify the first failure before changing code: + +- collection or import failure: package layout, test path, missing dependency, + or environment; +- fixture or marker failure: configuration, scope, registration, or setup; +- async/lifespan failure: event-loop ownership, startup, shutdown, or client + configuration; +- assertion failure: behavior, test data, or an intentionally changed public + contract; +- integration failure: isolate the external boundary before widening the test + suite. + +Hand general environment, lockfile, lint, type-check, packaging, or CI failures +to `diagnose-python-project`, `python-package-workflow`, or +`python-ci-workflow` rather than turning this into a generic maintenance skill. + +## Output Shape + +Return: + +1. `Test boundary`: unit, integration, client, artifact, or full suite. +2. `Command`: exact `uv` command and package or path scope. +3. `Configuration`: markers, fixtures, async support, or no change. +4. `Evidence`: tests added or run and concise results. +5. `Residual risk`: live dependency, unrun integration lane, coverage, or CI + limitation. + +## Guardrails + +- Do not add coverage tooling or thresholds without a concrete need. +- Do not make unit tests depend on a live network, production service, or + machine-local secret. +- Do not use `sys.path` edits to hide a package-layout problem. +- Do not leave the old `uv-pytest-unit-testing` skill name, profile path, or + routing surface behind after this rename. + +## References + +- `references/pytest-workflow.md` +- `references/uv-workspace-testing.md` +- `references/customization.md` +- `references/interactive-customization.md` +- [pytest documentation](https://docs.pytest.org/en/stable/) +- [FastAPI async tests](https://fastapi.tiangolo.com/advanced/async-tests/) +- [FastAPI dependency overrides](https://fastapi.tiangolo.com/advanced/testing-dependencies/) +- [FastMCP server testing](https://gofastmcp.com/servers/testing) diff --git a/plugins/python-skills/skills/python-testing-workflow/agents/openai.yaml b/plugins/python-skills/skills/python-testing-workflow/agents/openai.yaml new file mode 100644 index 000000000..7a7df86f3 --- /dev/null +++ b/plugins/python-skills/skills/python-testing-workflow/agents/openai.yaml @@ -0,0 +1,8 @@ +interface: + display_name: "Python Testing Workflow" + short_description: "Set up, run, and diagnose pytest through uv." + brand_color: "#B45309" + default_prompt: "Use $python-testing-workflow to inspect the Python test shape, choose unit, integration, client, or artifact coverage, keep workspace targeting explicit, run pytest through uv, and explain the first meaningful failure." + +policy: + allow_implicit_invocation: true diff --git a/plugins/python-skills/skills/uv-pytest-unit-testing/assets/profiles/bootstrap_pytest_uv.config.yaml b/plugins/python-skills/skills/python-testing-workflow/assets/profiles/bootstrap_pytest_uv.config.yaml similarity index 71% rename from plugins/python-skills/skills/uv-pytest-unit-testing/assets/profiles/bootstrap_pytest_uv.config.yaml rename to plugins/python-skills/skills/python-testing-workflow/assets/profiles/bootstrap_pytest_uv.config.yaml index 58013cbb2..318287547 100644 --- a/plugins/python-skills/skills/uv-pytest-unit-testing/assets/profiles/bootstrap_pytest_uv.config.yaml +++ b/plugins/python-skills/skills/python-testing-workflow/assets/profiles/bootstrap_pytest_uv.config.yaml @@ -1,4 +1,4 @@ -# uv-pytest-unit-testing bootstrap config profile +# python-testing-workflow bootstrap config profile # Use with: scripts/bootstrap_pytest_uv.sh --config workspace_root: "." diff --git a/plugins/python-skills/skills/uv-pytest-unit-testing/assets/profiles/run_pytest_uv.config.yaml b/plugins/python-skills/skills/python-testing-workflow/assets/profiles/run_pytest_uv.config.yaml similarity index 68% rename from plugins/python-skills/skills/uv-pytest-unit-testing/assets/profiles/run_pytest_uv.config.yaml rename to plugins/python-skills/skills/python-testing-workflow/assets/profiles/run_pytest_uv.config.yaml index 8eb0c9177..8d57f2f01 100644 --- a/plugins/python-skills/skills/uv-pytest-unit-testing/assets/profiles/run_pytest_uv.config.yaml +++ b/plugins/python-skills/skills/python-testing-workflow/assets/profiles/run_pytest_uv.config.yaml @@ -1,4 +1,4 @@ -# uv-pytest-unit-testing run config profile +# python-testing-workflow run config profile # Use with: scripts/run_pytest_uv.sh --config workspace_root: "." diff --git a/plugins/python-skills/skills/uv-pytest-unit-testing/references/customization.md b/plugins/python-skills/skills/python-testing-workflow/references/customization.md similarity index 95% rename from plugins/python-skills/skills/uv-pytest-unit-testing/references/customization.md rename to plugins/python-skills/skills/python-testing-workflow/references/customization.md index 920222d0f..44fe163dc 100644 --- a/plugins/python-skills/skills/uv-pytest-unit-testing/references/customization.md +++ b/plugins/python-skills/skills/python-testing-workflow/references/customization.md @@ -1,6 +1,6 @@ # Customization Guide -Use this reference when you need to change the defaults shipped by `uv-pytest-unit-testing`. +Use this reference when you need to change the defaults shipped by `python-testing-workflow`. ## High-Impact Knobs diff --git a/plugins/python-skills/skills/uv-pytest-unit-testing/references/interactive-customization.md b/plugins/python-skills/skills/python-testing-workflow/references/interactive-customization.md similarity index 87% rename from plugins/python-skills/skills/uv-pytest-unit-testing/references/interactive-customization.md rename to plugins/python-skills/skills/python-testing-workflow/references/interactive-customization.md index f61796089..4d5c2c23e 100644 --- a/plugins/python-skills/skills/uv-pytest-unit-testing/references/interactive-customization.md +++ b/plugins/python-skills/skills/python-testing-workflow/references/interactive-customization.md @@ -27,8 +27,8 @@ Run script keys: 1. CLI flags 2. `--config` file -3. Repo profile: `.codex/profiles/uv-pytest-unit-testing/customization.yaml` -4. Global profile: `~/.config/gaelic-ghost/python-skills/uv-pytest-unit-testing/customization.yaml` +3. Repo profile: `.codex/profiles/python-testing-workflow/customization.yaml` +4. Global profile: `~/.config/gaelic-ghost/python-skills/python-testing-workflow/customization.yaml` 5. Script defaults ## Reset and Cleanup diff --git a/plugins/python-skills/skills/uv-pytest-unit-testing/references/pytest-workflow.md b/plugins/python-skills/skills/python-testing-workflow/references/pytest-workflow.md similarity index 100% rename from plugins/python-skills/skills/uv-pytest-unit-testing/references/pytest-workflow.md rename to plugins/python-skills/skills/python-testing-workflow/references/pytest-workflow.md diff --git a/plugins/python-skills/skills/uv-pytest-unit-testing/references/uv-workspace-testing.md b/plugins/python-skills/skills/python-testing-workflow/references/uv-workspace-testing.md similarity index 100% rename from plugins/python-skills/skills/uv-pytest-unit-testing/references/uv-workspace-testing.md rename to plugins/python-skills/skills/python-testing-workflow/references/uv-workspace-testing.md diff --git a/plugins/python-skills/skills/uv-pytest-unit-testing/scripts/bootstrap_pytest_uv.sh b/plugins/python-skills/skills/python-testing-workflow/scripts/bootstrap_pytest_uv.sh similarity index 99% rename from plugins/python-skills/skills/uv-pytest-unit-testing/scripts/bootstrap_pytest_uv.sh rename to plugins/python-skills/skills/python-testing-workflow/scripts/bootstrap_pytest_uv.sh index 702e6ea9e..11abfb633 100755 --- a/plugins/python-skills/skills/uv-pytest-unit-testing/scripts/bootstrap_pytest_uv.sh +++ b/plugins/python-skills/skills/python-testing-workflow/scripts/bootstrap_pytest_uv.sh @@ -7,7 +7,7 @@ PACKAGE_NAME="" WITH_COV=0 DRY_RUN=0 -SKILL_NAME="uv-pytest-unit-testing" +SKILL_NAME="python-testing-workflow" SCRIPT_DIR="${0:A:h}" REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" GLOBAL_PROFILE="$HOME/.config/gaelic-ghost/python-skills/$SKILL_NAME/customization.yaml" diff --git a/plugins/python-skills/skills/uv-pytest-unit-testing/scripts/run_pytest_uv.sh b/plugins/python-skills/skills/python-testing-workflow/scripts/run_pytest_uv.sh similarity index 99% rename from plugins/python-skills/skills/uv-pytest-unit-testing/scripts/run_pytest_uv.sh rename to plugins/python-skills/skills/python-testing-workflow/scripts/run_pytest_uv.sh index 26090d340..255e247db 100755 --- a/plugins/python-skills/skills/uv-pytest-unit-testing/scripts/run_pytest_uv.sh +++ b/plugins/python-skills/skills/python-testing-workflow/scripts/run_pytest_uv.sh @@ -6,7 +6,7 @@ WORKSPACE_ROOT="$(pwd)" PACKAGE_NAME="" TEST_PATH="" -SKILL_NAME="uv-pytest-unit-testing" +SKILL_NAME="python-testing-workflow" SCRIPT_DIR="${0:A:h}" REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" GLOBAL_PROFILE="$HOME/.config/gaelic-ghost/python-skills/$SKILL_NAME/customization.yaml" diff --git a/plugins/python-skills/skills/uv-pytest-unit-testing/SKILL.md b/plugins/python-skills/skills/uv-pytest-unit-testing/SKILL.md deleted file mode 100644 index 9f25c5cf3..000000000 --- a/plugins/python-skills/skills/uv-pytest-unit-testing/SKILL.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -name: uv-pytest-unit-testing -description: Set up and run unit tests for Python uv projects and uv workspaces with pytest. Use when creating or updating pytest configuration in pyproject.toml, installing pytest dev dependencies with uv, running tests in a workspace member package via `uv run --package`, customizing pytest workflow defaults through layered YAML profiles, organizing tests with fixtures/markers/parametrize, or troubleshooting test discovery and import failures. -license: Apache-2.0 -compatibility: Designed for Codex and compatible Agent Skills clients on macOS with uv-managed Python projects, pytest, and shell access for the bundled scripts. -metadata: - owner: gaelic-ghost - repo: python-skills - category: python-testing -allowed-tools: Bash(uv:*) Read ---- - -# Uv Pytest Unit Testing - -## Purpose - -Use this skill to standardize pytest setup and execution for uv-managed Python repositories, including single-project repos and uv workspaces. - -## When To Use - -- Use this skill for pytest setup, execution, and troubleshooting in `uv`-managed repositories. -- Use this skill when the user wants package-targeted pytest runs for a workspace member. -- Keep scope on test setup and execution; do not use this as a generic repo bootstrap skill. - -## Primary Workflow - -1. Detect repository mode. - - Treat the repo as a workspace when `pyproject.toml` defines `[tool.uv.workspace]`. - - Treat it as a single project otherwise. -2. Bootstrap pytest dependencies and baseline config: - - `scripts/bootstrap_pytest_uv.sh --workspace-root ` - - add `--package ` for workspace-member setup - - add `--with-cov` when the task explicitly wants `pytest-cov` - - add `--dry-run` when previewing changes -3. Run tests: - - `scripts/run_pytest_uv.sh --workspace-root ` - - `scripts/run_pytest_uv.sh --workspace-root --package ` -4. Troubleshoot failures in this order: - - command context - - test discovery layout - - marker registration - - import-path assumptions - -## Test Authoring Guidance - -- Keep fast unit tests under `tests/unit` and integration-heavy tests under `tests/integration` when repo size warrants separation. -- Use fixtures for setup reuse, and keep fixture scope minimal (`function` by default). -- Use `@pytest.mark.parametrize` for matrix-style cases instead of hand-written loops. -- Use `monkeypatch` for environment variables and runtime dependency replacement. -- When generated projects use `pydantic-settings`, prefer overriding environment variables or the settings dependency rather than mutating committed `.env` files in tests. -- Register custom marks in config to avoid marker warnings. - -## Automation Suitability - -- Codex App automation: High. Strong recurring fit for test health checks, failure triage, and drift detection. -- Codex CLI automation: High. Strong fit for non-interactive test setup and targeted test sweeps. - -## Codex App Automation Prompt Template - -```markdown -Use $uv-pytest-unit-testing. - -Scope boundaries: -- Work only inside . -- Operate only on pytest setup and test execution tasks. -- Do not perform unrelated code refactors. - -Task: -1. Detect repository mode from /pyproject.toml. -2. If is TRUE, run: - `scripts/bootstrap_pytest_uv.sh --workspace-root --dry-run` -3. If is FALSE, run: - `scripts/bootstrap_pytest_uv.sh --workspace-root ` -4. Run tests with: - `scripts/run_pytest_uv.sh --workspace-root -- ` -5. Keep package-targeted runs explicit when is set. - -Output contract: -1. STATUS: PASS or FAIL -2. SETUP: what bootstrap actions ran -3. TEST_RESULTS: concise pass/fail summary -4. FAILURES: grouped likely causes -5. NEXT_STEPS: minimal remediation actions -``` - -## Codex CLI Automation Prompt Template - -```bash -codex exec --full-auto --sandbox workspace-write --cd "" "" -``` - -`` template: - -```markdown -Use $uv-pytest-unit-testing. -Limit scope to pytest setup and execution in . -Run bootstrap in dry-run or real mode based on . -Run tests with explicit package targeting when is set. -Return STATUS, setup actions, concise test summary, grouped likely causes for failures, and minimal next steps. -``` - -## Customization Placeholders - -- `` -- `` -- `` -- `` -- `` -- `` -- `` -- `` -- `` - -## Interactive Customization Workflow - -1. Ask whether users want bootstrap mode or run mode. -2. Gather workspace root and optional package target. -3. For bootstrap mode, gather `with_cov` and `dry_run`. -4. For run mode, gather optional test path and optional pytest args. -5. Return both: -- A YAML profile for durable reuse. -- The exact command to run. -6. Use this precedence order: -- CLI flags -- `--config` profile file -- `.codex/profiles/uv-pytest-unit-testing/customization.yaml` -- `~/.config/gaelic-ghost/python-skills/uv-pytest-unit-testing/customization.yaml` -- Script defaults -7. If users want temporary reset behavior: -- `--bypassing-all-profiles` -- `--bypassing-repo-profile` -- `--deleting-repo-profile` -8. If users provide no customization or profile files, keep existing script defaults unchanged. -9. See [`references/interactive-customization.md`](references/interactive-customization.md) for schema and examples. - -## Outputs - -- `status` - - `success`: setup or test execution completed - - `blocked`: repo shape or prerequisites prevented the run - - `failed`: bootstrap or test execution ran but did not complete cleanly -- `path_type` - - `primary`: canonical shell entrypoints completed -- `output` - - setup actions taken - - exact run command used - - concise failure grouping when applicable - -## Guardrails - -- Require `uv` for all installation and execution paths. -- Require an existing `pyproject.toml` under `--workspace-root`. -- Keep package targeting explicit when operating on a workspace member. - -## References - -- `references/pytest-workflow.md` -- `references/uv-workspace-testing.md` -- `references/customization.md` -- `references/interactive-customization.md` - -## Script Inventory - -- `scripts/bootstrap_pytest_uv.sh` -- `scripts/run_pytest_uv.sh` diff --git a/plugins/python-skills/skills/uv-pytest-unit-testing/agents/openai.yaml b/plugins/python-skills/skills/uv-pytest-unit-testing/agents/openai.yaml deleted file mode 100644 index 34103eadb..000000000 --- a/plugins/python-skills/skills/uv-pytest-unit-testing/agents/openai.yaml +++ /dev/null @@ -1,8 +0,0 @@ -interface: - display_name: "Pytest for UV Workspaces" - short_description: "Set up and run pytest with uv." - brand_color: "#B45309" - default_prompt: "Use $uv-pytest-unit-testing to detect repo shape, optionally apply layered customization profiles, bootstrap pytest for a uv project or workspace, keep package targeting explicit, account for pydantic-settings-based configuration, and run tests through the canonical shell entrypoints." - -policy: - allow_implicit_invocation: true diff --git a/plugins/python-skills/tests/test_build_python_agent_service_skill.py b/plugins/python-skills/tests/test_build_python_agent_service_skill.py index 050889f2b..2b8e0bbd6 100644 --- a/plugins/python-skills/tests/test_build_python_agent_service_skill.py +++ b/plugins/python-skills/tests/test_build_python_agent_service_skill.py @@ -34,3 +34,10 @@ def test_agent_service_interface_mentions_exact_model_and_approval() -> None: assert interface["display_name"] == "Build Python Agent Service" assert "exact model" in interface["default_prompt"] assert "approval gate" in interface["default_prompt"] + + +def test_agent_service_uses_uv_without_unrestricted_python_tool_access() -> None: + skill = (SKILL_ROOT / "SKILL.md").read_text(encoding="utf-8") + + assert "Bash(python:*)" not in skill + assert "Bash(uv:*)" in skill diff --git a/plugins/python-skills/tests/test_plugin_smoke.py b/plugins/python-skills/tests/test_plugin_smoke.py index a51bd6a37..0db906d51 100644 --- a/plugins/python-skills/tests/test_plugin_smoke.py +++ b/plugins/python-skills/tests/test_plugin_smoke.py @@ -44,6 +44,52 @@ def test_plugin_manifest_and_marketplace_contract() -> None: assert not (REPO_ROOT / "README.md").exists() +def test_fastmcp_docs_tool_is_host_provided_not_packaged_dependency() -> None: + for skill_name in ("bootstrap-python-mcp-service", "integrate-fastapi-fastmcp"): + skill_root = REPO_ROOT / "skills" / skill_name + metadata = (skill_root / "agents" / "openai.yaml").read_text() + skill = (skill_root / "SKILL.md").read_text() + + assert "fastmcp_docs" not in metadata + assert "does not package that server" in skill + + +def test_service_and_testing_inventory_replaces_the_old_pytest_skill() -> None: + expected = { + "fastapi-service-workflow", + "fastmcp-service-workflow", + "python-testing-workflow", + } + actual = {path.parent.name for path in (REPO_ROOT / "skills").glob("*/SKILL.md")} + + assert expected <= actual + assert "uv-pytest-unit-testing" not in actual + + for skill_name in expected: + assert (REPO_ROOT / "skills" / skill_name / "agents" / "openai.yaml").is_file() + + +def test_bootstrap_skills_share_one_contract_reference() -> None: + contract = REPO_ROOT / "shared" / "bootstrap-contract.md" + assert contract.is_file() + + for skill_name in ( + "bootstrap-uv-python-workspace", + "bootstrap-python-service", + "bootstrap-python-mcp-service", + ): + skill = (REPO_ROOT / "skills" / skill_name / "SKILL.md").read_text() + assert "../../shared/bootstrap-contract.md" in skill + + +def test_python_testing_scripts_use_the_replacement_profile_name() -> None: + scripts_root = REPO_ROOT / "skills" / "python-testing-workflow" / "scripts" + for script_name in ("bootstrap_pytest_uv.sh", "run_pytest_uv.sh"): + script = (scripts_root / script_name).read_text() + assert 'SKILL_NAME="python-testing-workflow"' in script + assert "uv-pytest-unit-testing" not in script + + def test_fastapi_scaffold_smoke(tmp_path: Path) -> None: target = tmp_path / "demo-api" run_command( diff --git a/scripts/export_hermes_skills.py b/scripts/export_hermes_skills.py index 5a9a60f6d..e959282a4 100644 --- a/scripts/export_hermes_skills.py +++ b/scripts/export_hermes_skills.py @@ -143,7 +143,12 @@ "build-dotnet-agent-service", ) PRODUCTIVITY_SKILLS = ("design-n8n-agent-workflow",) -PYTHON_SKILLS = ("build-python-agent-service",) +PYTHON_SKILLS = ( + "build-python-agent-service", + "fastapi-service-workflow", + "fastmcp-service-workflow", + "python-testing-workflow", +) JVM_SKILLS = ("build-jvm-agent-service",) CLOUD_DEPLOYMENT_SKILLS = ("cloud-deployment-routing-workflow",) EXPORTED_SKILLS = ( diff --git a/skills.sh.json b/skills.sh.json index 4b3a82f5c..252138b90 100644 --- a/skills.sh.json +++ b/skills.sh.json @@ -112,7 +112,10 @@ { "title": "Python Skills", "skills": [ - "build-python-agent-service" + "build-python-agent-service", + "fastapi-service-workflow", + "fastmcp-service-workflow", + "python-testing-workflow" ] }, { diff --git a/skills/build-python-agent-service/SKILL.md b/skills/build-python-agent-service/SKILL.md index 62d6efe2a..5f8b575ee 100644 --- a/skills/build-python-agent-service/SKILL.md +++ b/skills/build-python-agent-service/SKILL.md @@ -7,7 +7,7 @@ metadata: owner: gaelic-ghost repo: python-skills category: python-agent-service -allowed-tools: Read Bash(rg:*) Bash(git:*) Bash(uv:*) Bash(python:*) +allowed-tools: Read Bash(rg:*) Bash(git:*) Bash(uv:*) --- # Build Python Agent Service diff --git a/skills/fastapi-service-workflow/SKILL.md b/skills/fastapi-service-workflow/SKILL.md new file mode 100644 index 000000000..1210141da --- /dev/null +++ b/skills/fastapi-service-workflow/SKILL.md @@ -0,0 +1,89 @@ +--- +name: fastapi-service-workflow +description: Maintain existing uv-managed FastAPI services, including route and dependency composition, typed settings, lifespan, async and integration testing, OpenAPI review, deployment-readiness handoff, and service-specific diagnostics. +license: Apache-2.0 +compatibility: Designed for Codex and compatible Agent Skills clients maintaining FastAPI services on macOS with uv, typed configuration, async Python, and the repository's existing deployment tools. +metadata: + owner: gaelic-ghost + repo: python-skills + category: python-fastapi +allowed-tools: Read Bash(rg:*) Bash(git:*) Bash(uv:*) +--- + +# FastAPI Service Workflow + +## Purpose + +Maintain an existing FastAPI service without turning routing, application +lifecycle, domain logic, deployment, and MCP integration into one layer. Keep +HTTP adapters thin around typed domain behavior and make startup, shutdown, +configuration, and public API changes explicit. + +## Workflow + +1. Inspect `pyproject.toml`, app entrypoint, routers, dependencies, settings, + lifespan, tests, OpenAPI output, CI, and deployment configuration. +2. Classify the requested change as route composition, request/response model, + dependency, settings, lifecycle, async boundary, public OpenAPI contract, or + deployment-readiness work. +3. Keep route handlers focused on HTTP translation. Put reusable behavior in + domain modules or existing service boundaries rather than duplicating it + across routes, CLI commands, or MCP tools. +4. Keep settings typed and injectable. Store safe defaults separately from + machine-local or deployment secrets; use dependency overrides in tests. +5. Use one lifespan contract for resources such as pools, clients, queues, and + background workers. Combine lifespans deliberately when mounting another + ASGI application instead of silently replacing startup or shutdown work. +6. Review the OpenAPI effect of public routes, models, status codes, operation + IDs, security requirements, and deprecations. Treat incompatible changes as + an API compatibility decision. +7. Run focused HTTP and async tests, then the repository's configured checks: + ```bash + uv run pytest + uv run ruff check . + uv run mypy . + ``` +8. Report deployment readiness separately: configuration source, migrations, + health endpoint, logs, timeouts, workers, and external dependencies. Do not + deploy unless the user asks for that operation. + +## Testing And Diagnostics + +Use dependency overrides for paid, privileged, or nondeterministic services and +clear them after each test. Use an async client for async behavior, and make +lifespan execution explicit when tests depend on startup resources. + +Diagnose service failures in this order: import or app factory, settings, +lifespan, route/dependency resolution, response validation, async boundary, +then external integration. Hand generic lockfile, package, CI, or tool failures +to their existing Python workflows. + +## Handoffs + +- New service scaffolding: `bootstrap-python-service`. +- Generic implementation and package structure: `build-python-project`. +- FastAPI plus FastMCP in one codebase: `integrate-fastapi-fastmcp`. +- MCP service maintenance: `fastmcp-service-workflow`. +- Package, CI, testing, tooling, and upgrade work: their corresponding Python + workflows. + +## Output Shape + +Return the service boundary changed, HTTP/OpenAPI impact, settings and +lifespan effect, tests and commands run, deployment-readiness evidence, and +residual risk. + +## Guardrails + +- Do not add a repository, manager, or service wrapper when a route can call an + existing typed domain boundary directly. +- Do not run a service, migration, external write, or deployment merely to + validate static guidance without user approval. +- Do not change public OpenAPI behavior silently. + +## References + +- [FastAPI lifespan events](https://fastapi.tiangolo.com/advanced/events/) +- [FastAPI settings](https://fastapi.tiangolo.com/advanced/settings/) +- [FastAPI dependency overrides](https://fastapi.tiangolo.com/advanced/testing-dependencies/) +- [FastAPI async tests](https://fastapi.tiangolo.com/advanced/async-tests/) diff --git a/skills/fastapi-service-workflow/agents/openai.yaml b/skills/fastapi-service-workflow/agents/openai.yaml new file mode 100644 index 000000000..7abdbf506 --- /dev/null +++ b/skills/fastapi-service-workflow/agents/openai.yaml @@ -0,0 +1,8 @@ +interface: + display_name: "FastAPI Service Workflow" + short_description: "Maintain FastAPI routes, settings, lifespan, OpenAPI, and service tests." + brand_color: "#0F766E" + default_prompt: "Use $fastapi-service-workflow to inspect this existing FastAPI service, preserve its typed settings and lifespan contract, implement the requested route or dependency change, review the OpenAPI impact, and run focused uv validation." + +policy: + allow_implicit_invocation: true diff --git a/skills/fastmcp-service-workflow/SKILL.md b/skills/fastmcp-service-workflow/SKILL.md new file mode 100644 index 000000000..7b6e91416 --- /dev/null +++ b/skills/fastmcp-service-workflow/SKILL.md @@ -0,0 +1,82 @@ +--- +name: fastmcp-service-workflow +description: Maintain existing uv-managed FastMCP servers, including transport and lifespan behavior, tool/resource/prompt curation, authorization and input boundaries, client integration tests, generated-surface review, and upgrade diagnostics. +license: Apache-2.0 +compatibility: Designed for Codex and compatible Agent Skills clients maintaining FastMCP servers on macOS with uv, the installed FastMCP version, and the repository's existing transport and deployment tools. +metadata: + owner: gaelic-ghost + repo: python-skills + category: python-fastmcp +allowed-tools: Read Bash(rg:*) Bash(git:*) Bash(uv:*) +--- + +# FastMCP Service Workflow + +## Purpose + +Maintain a curated FastMCP server as an application surface, not a mechanical +mirror of HTTP routes. Keep tool, resource, and prompt design user-oriented; +make transport, authentication, authorization, lifespan, and side-effect +boundaries explicit. + +## Workflow + +1. Inspect the installed FastMCP version, `pyproject.toml`, server entrypoint, + component definitions, transport, lifespan, auth configuration, tests, and + deployment configuration before changing behavior. +2. Classify each public capability: + - a tool for an action or bounded computation; + - a resource or template for read-oriented data; + - a prompt for a reusable message workflow. +3. Keep implementation logic in existing typed domain boundaries. Do not expose + transport-centric route names, broad autogenerated APIs, secrets, or raw + infrastructure controls as MCP capabilities. +4. Choose transport deliberately. STDIO clients own the server process and its + environment; HTTP is the normal production transport. Make every required + configuration value explicit for the selected transport. +5. Define authorization at the component or server boundary when the HTTP + deployment needs it. Do not infer identity or permissions from a model's + request, and do not claim HTTP OAuth checks protect STDIO transport. +6. Treat `FastMCP.from_fastapi(...)` and OpenAPI imports as review inputs. + Curate names, parameter shapes, errors, and capability boundaries before + keeping generated output as a public server surface. +7. Test through an in-memory FastMCP client first, then add transport and auth + integration tests only where those are part of the deployment contract. +8. Run the repository's configured checks and report any untested transport, + authorization, or external-write boundary separately. + +## Version And Documentation Discipline + +Use the installed FastMCP version and its release notes for implementation +decisions. The public FastMCP documentation tracks `main` and can describe +unreleased behavior. Use a host-provided `fastmcp_docs` tool only when one is +already configured; this plugin does not package it. + +## Handoffs + +- New MCP scaffold: `bootstrap-python-mcp-service`. +- FastAPI/FastMCP coexistence or mounting: `integrate-fastapi-fastmcp`. +- FastAPI service maintenance: `fastapi-service-workflow`. +- Generic testing, package, CI, tooling, and upgrade work: the corresponding + Python workflows. + +## Output Shape + +Return the component and transport boundary changed, installed FastMCP version, +authorization effect, test commands and results, deployment-readiness effect, +and residual risk. + +## Guardrails + +- Do not add a generated route mirror as a long-term MCP API without curation. +- Do not expose write-capable tools without explicit authorization, input, + timeout, idempotency, and approval behavior. +- Do not run a production transport, deploy a server, or execute live writes + only to validate the skill. + +## References + +- [FastMCP client testing](https://gofastmcp.com/servers/testing) +- [FastMCP transports](https://gofastmcp.com/clients/transports) +- [FastMCP authorization](https://gofastmcp.com/servers/authorization) +- [FastMCP CLI](https://gofastmcp.com/cli/overview) diff --git a/skills/fastmcp-service-workflow/agents/openai.yaml b/skills/fastmcp-service-workflow/agents/openai.yaml new file mode 100644 index 000000000..da01051c8 --- /dev/null +++ b/skills/fastmcp-service-workflow/agents/openai.yaml @@ -0,0 +1,8 @@ +interface: + display_name: "FastMCP Service Workflow" + short_description: "Maintain FastMCP components, transports, authorization, and client tests." + brand_color: "#1D4ED8" + default_prompt: "Use $fastmcp-service-workflow to inspect this existing FastMCP server and installed version, curate the requested tool, resource, or prompt change, preserve transport and authorization boundaries, and validate it with a focused uv client test." + +policy: + allow_implicit_invocation: true diff --git a/skills/python-testing-workflow/SKILL.md b/skills/python-testing-workflow/SKILL.md new file mode 100644 index 000000000..9b0857470 --- /dev/null +++ b/skills/python-testing-workflow/SKILL.md @@ -0,0 +1,125 @@ +--- +name: python-testing-workflow +description: Set up, run, and improve Python tests in uv projects and workspaces. Use for pytest configuration, focused and package-targeted runs, fixtures, parametrization, async and integration tests, coverage, CI parity, or failure triage. +license: Apache-2.0 +compatibility: Designed for Codex and compatible Agent Skills clients on macOS with uv-managed Python projects, pytest, and shell access for the bundled setup and execution scripts. +metadata: + owner: gaelic-ghost + repo: python-skills + category: python-testing +allowed-tools: Bash(uv:*) Read +--- + +# Python Testing Workflow + +## Purpose + +Make Python tests describe behavior, run through `uv`, and give a focused +failure signal. Preserve the repository's existing test framework and markers; +use the bundled scripts only for pytest setup or repeatable package-targeted +runs. + +## Workflow + +1. Inspect `pyproject.toml`, existing tests, CI, markers, fixtures, package + layout, and workspace members before changing test configuration. +2. Choose the smallest useful test boundary: + - unit tests for pure behavior and fakeable dependencies; + - integration tests for framework, database, filesystem, network, or + process boundaries; + - a client test for public HTTP or MCP behavior; + - a package-artifact smoke test when package contents changed. +3. Run a focused check first: + ```bash + uv run pytest tests/unit + uv run pytest -k "auth and not slow" + uv run --package pytest + ``` +4. Add fixtures for reusable setup, keep their scope minimal, and use + `@pytest.mark.parametrize` for input/output matrices. +5. Use `monkeypatch`, dependency overrides, fakes, or disposable services at + the boundary rather than mutating committed configuration or calling a live + dependency during every test. +6. Use async tests only when the code under test is async. Configure the + repository's async test support explicitly and verify lifespan behavior when + the app owns startup or shutdown resources. +7. Run the relevant complete test selection, then the project's CI-equivalent + validation commands. Add coverage only when the user or repository has a + concrete coverage threshold or reporting need. + +## Setup And Execution Scripts + +For a new pytest setup or a repeatable workspace command, use the existing +scripts: + +```bash +scripts/bootstrap_pytest_uv.sh --workspace-root +scripts/bootstrap_pytest_uv.sh --workspace-root --package +scripts/run_pytest_uv.sh --workspace-root --package +scripts/run_pytest_uv.sh --workspace-root --path tests/integration -- -m integration +``` + +Use `--with-cov` only when the requested test contract needs `pytest-cov`. +Profiles use the `python-testing-workflow` name and should remain optional; +ordinary repositories should work from their checked-in `pyproject.toml` alone. + +## FastAPI And FastMCP Boundaries + +For FastAPI, override external dependencies with +`app.dependency_overrides`, reset them after the test, and use an async client +when the test itself needs async behavior. Ensure lifespan events run when the +application depends on them. + +For FastMCP, prefer an in-memory `Client(mcp)` test for deterministic server +behavior, then add transport or authorization integration tests only for the +configured deployment shape. Test listed and callable tools, readable +resources, and rendered prompts separately when each surface is public. + +## Failure Triage + +Classify the first failure before changing code: + +- collection or import failure: package layout, test path, missing dependency, + or environment; +- fixture or marker failure: configuration, scope, registration, or setup; +- async/lifespan failure: event-loop ownership, startup, shutdown, or client + configuration; +- assertion failure: behavior, test data, or an intentionally changed public + contract; +- integration failure: isolate the external boundary before widening the test + suite. + +Hand general environment, lockfile, lint, type-check, packaging, or CI failures +to `diagnose-python-project`, `python-package-workflow`, or +`python-ci-workflow` rather than turning this into a generic maintenance skill. + +## Output Shape + +Return: + +1. `Test boundary`: unit, integration, client, artifact, or full suite. +2. `Command`: exact `uv` command and package or path scope. +3. `Configuration`: markers, fixtures, async support, or no change. +4. `Evidence`: tests added or run and concise results. +5. `Residual risk`: live dependency, unrun integration lane, coverage, or CI + limitation. + +## Guardrails + +- Do not add coverage tooling or thresholds without a concrete need. +- Do not make unit tests depend on a live network, production service, or + machine-local secret. +- Do not use `sys.path` edits to hide a package-layout problem. +- Do not leave the old `uv-pytest-unit-testing` skill name, profile path, or + routing surface behind after this rename. + +## References + +- `references/pytest-workflow.md` +- `references/uv-workspace-testing.md` +- `references/customization.md` +- `references/interactive-customization.md` +- [pytest documentation](https://docs.pytest.org/en/stable/) +- [FastAPI async tests](https://fastapi.tiangolo.com/advanced/async-tests/) +- [FastAPI dependency overrides](https://fastapi.tiangolo.com/advanced/testing-dependencies/) +- [FastMCP server testing](https://gofastmcp.com/servers/testing) diff --git a/skills/python-testing-workflow/agents/openai.yaml b/skills/python-testing-workflow/agents/openai.yaml new file mode 100644 index 000000000..7a7df86f3 --- /dev/null +++ b/skills/python-testing-workflow/agents/openai.yaml @@ -0,0 +1,8 @@ +interface: + display_name: "Python Testing Workflow" + short_description: "Set up, run, and diagnose pytest through uv." + brand_color: "#B45309" + default_prompt: "Use $python-testing-workflow to inspect the Python test shape, choose unit, integration, client, or artifact coverage, keep workspace targeting explicit, run pytest through uv, and explain the first meaningful failure." + +policy: + allow_implicit_invocation: true diff --git a/skills/python-testing-workflow/assets/profiles/bootstrap_pytest_uv.config.yaml b/skills/python-testing-workflow/assets/profiles/bootstrap_pytest_uv.config.yaml new file mode 100644 index 000000000..318287547 --- /dev/null +++ b/skills/python-testing-workflow/assets/profiles/bootstrap_pytest_uv.config.yaml @@ -0,0 +1,7 @@ +# python-testing-workflow bootstrap config profile +# Use with: scripts/bootstrap_pytest_uv.sh --config + +workspace_root: "." +package: "" +with_cov: false +dry_run: false diff --git a/skills/python-testing-workflow/assets/profiles/run_pytest_uv.config.yaml b/skills/python-testing-workflow/assets/profiles/run_pytest_uv.config.yaml new file mode 100644 index 000000000..8d57f2f01 --- /dev/null +++ b/skills/python-testing-workflow/assets/profiles/run_pytest_uv.config.yaml @@ -0,0 +1,6 @@ +# python-testing-workflow run config profile +# Use with: scripts/run_pytest_uv.sh --config + +workspace_root: "." +package: "" +path: "" diff --git a/skills/python-testing-workflow/references/customization.md b/skills/python-testing-workflow/references/customization.md new file mode 100644 index 000000000..44fe163dc --- /dev/null +++ b/skills/python-testing-workflow/references/customization.md @@ -0,0 +1,18 @@ +# Customization Guide + +Use this reference when you need to change the defaults shipped by `python-testing-workflow`. + +## High-Impact Knobs + +- baseline `tool.pytest.ini_options` content +- coverage behavior and optional dependency installation +- package-targeted run expectations for workspaces +- test path and marker conventions +- CI-oriented command examples + +## Audit Checklist After Changes + +- dry-run and real bootstrap flows still match the docs +- root-project and `--package` command examples still work +- the troubleshooting order still reflects the real intended workflow +- repo-level validation still passes after doc and metadata updates diff --git a/skills/python-testing-workflow/references/interactive-customization.md b/skills/python-testing-workflow/references/interactive-customization.md new file mode 100644 index 000000000..4d5c2c23e --- /dev/null +++ b/skills/python-testing-workflow/references/interactive-customization.md @@ -0,0 +1,44 @@ +# Interactive Customization + +## Checklist + +1. Choose script mode: +- bootstrap script: `bootstrap_pytest_uv.sh` +- run script: `run_pytest_uv.sh` +2. Gather `workspace_root` and optional `package`. +3. For bootstrap mode, confirm `with_cov` and `dry_run`. +4. For run mode, gather optional `path` and optional pytest passthrough args. +5. Return both YAML profile and exact command. + +## Schema + +Bootstrap script keys: +- `workspace_root` (string, default current directory) +- `package` (string, optional) +- `with_cov` (bool, default `false`) +- `dry_run` (bool, default `false`) + +Run script keys: +- `workspace_root` (string, default current directory) +- `package` (string, optional) +- `path` (string, optional) + +## Source Precedence + +1. CLI flags +2. `--config` file +3. Repo profile: `.codex/profiles/python-testing-workflow/customization.yaml` +4. Global profile: `~/.config/gaelic-ghost/python-skills/python-testing-workflow/customization.yaml` +5. Script defaults + +## Reset and Cleanup + +- `--bypassing-all-profiles`: ignore global and repo profile for this run. +- `--bypassing-repo-profile`: ignore only repo profile for this run. +- `--deleting-repo-profile`: delete repo profile before running. + +## Troubleshooting + +- Unknown key in YAML: script exits with an error naming the key. +- Missing explicit config file with `--config`: script exits with an error. +- Ensure `--` is used for pytest passthrough args in run mode. diff --git a/skills/python-testing-workflow/references/pytest-workflow.md b/skills/python-testing-workflow/references/pytest-workflow.md new file mode 100644 index 000000000..6206fc58c --- /dev/null +++ b/skills/python-testing-workflow/references/pytest-workflow.md @@ -0,0 +1,70 @@ +# Pytest Workflow for uv Projects + +## Quick Start + +1. Install pytest as a dev dependency. +- Root project: `uv add --dev pytest` +- Workspace member: `uv add --package --dev pytest` + +2. Run tests. +- Root project: `uv run pytest` +- Targeted path: `uv run pytest tests/unit` +- Expression filter: `uv run pytest -k "auth and not slow"` + +3. Optional coverage guidance. +- Install plugin: `uv add --dev pytest-cov` +- Run with report: `uv run pytest --cov --cov-report=term-missing` + +## Baseline pyproject.toml config + +Use `tool.pytest.ini_options` for project defaults: + +```toml +[tool.pytest.ini_options] +addopts = "-ra" +testpaths = ["tests"] +python_files = ["test_*.py", "*_test.py"] +``` + +Common optional fields: + +```toml +[tool.pytest.ini_options] +markers = [ + "slow: marks tests as slow", + "integration: marks tests as integration", +] +xfail_strict = true +``` + +## Test Organization + +- Put unit tests in `tests/unit` and integration tests in `tests/integration` when useful. +- Keep test modules deterministic and independent. +- Prefer fixtures over repeated setup blocks. + +## Fixtures, Parametrize, Monkeypatch + +- Place shared fixtures in `tests/conftest.py`. +- Use `@pytest.mark.parametrize` for input/output matrices. +- Use `monkeypatch` for env vars and side-effectful dependencies. + +## Troubleshooting + +1. No tests collected: +- Confirm naming patterns (`test_*.py`, `*_test.py`) and path selection. + +2. Marker warnings: +- Register custom markers under `tool.pytest.ini_options.markers`. + +3. Import errors: +- Confirm package layout and current run context. +- Prefer running from repository root with uv to preserve expected module resolution. + +## References + +- https://docs.pytest.org/en/stable/getting-started.html#get-started +- https://docs.pytest.org/en/stable/example/simple.html +- https://docs.pytest.org/en/stable/how-to/index.html#how-to +- https://docs.pytest.org/en/stable/reference/index.html#reference +- https://docs.pytest.org/en/stable/explanation/index.html#explanation diff --git a/skills/python-testing-workflow/references/uv-workspace-testing.md b/skills/python-testing-workflow/references/uv-workspace-testing.md new file mode 100644 index 000000000..743178d25 --- /dev/null +++ b/skills/python-testing-workflow/references/uv-workspace-testing.md @@ -0,0 +1,45 @@ +# uv Workspace Testing + +## Detect Context + +- Single project: one package, run tests with `uv run pytest`. +- Workspace: repository defines `[tool.uv.workspace]`, run member tests with `uv run --package pytest`. + +## Command Patterns + +1. Run all tests for root project: +- `uv run pytest` + +2. Run tests for one workspace member package: +- `uv run --package pytest` + +3. Run only a path in one workspace member package: +- `uv run --package pytest tests/unit` + +4. Forward selectors/options: +- `uv run --package pytest -k "api and not slow" -m "not integration"` + +## Dependency Setup Patterns + +- Root project dev dependency: +- `uv add --dev pytest` + +- Workspace member dev dependency: +- `uv add --package --dev pytest` + +- Optional coverage plugin: +- `uv add --dev pytest-cov` +- `uv add --package --dev pytest-cov` + +## Practical Guardrails + +- Install dependencies in the same context used to run tests (root vs package). +- Use `--package` consistently when the target is a workspace member. +- Keep package-specific test commands explicit in automation scripts to avoid accidental root-only execution. + +## References + +- https://docs.astral.sh/uv/concepts/projects/workspaces/ +- https://docs.astral.sh/uv/reference/cli/#uv-run +- https://pydevtools.com/handbook/how-to/how-to-run-tests-using-uv/ +- https://pydevtools.com/handbook/tutorial/setting-up-testing-with-pytest-and-uv/ diff --git a/skills/python-testing-workflow/scripts/bootstrap_pytest_uv.sh b/skills/python-testing-workflow/scripts/bootstrap_pytest_uv.sh new file mode 100755 index 000000000..11abfb633 --- /dev/null +++ b/skills/python-testing-workflow/scripts/bootstrap_pytest_uv.sh @@ -0,0 +1,279 @@ +#!/usr/bin/env zsh +emulate -L zsh +set -euo pipefail + +WORKSPACE_ROOT="$(pwd)" +PACKAGE_NAME="" +WITH_COV=0 +DRY_RUN=0 + +SKILL_NAME="python-testing-workflow" +SCRIPT_DIR="${0:A:h}" +REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" +GLOBAL_PROFILE="$HOME/.config/gaelic-ghost/python-skills/$SKILL_NAME/customization.yaml" +REPO_PROFILE="$REPO_ROOT/.codex/profiles/$SKILL_NAME/customization.yaml" + +CONFIG_PATH="" +BYPASS_ALL_PROFILES=0 +BYPASS_REPO_PROFILE=0 +DELETE_REPO_PROFILE=0 + +usage() { + cat <<'USAGE' +Usage: bootstrap_pytest_uv.sh [--workspace-root PATH] [--package NAME] [--with-cov] [--dry-run] [--config PATH] + +Options: + --workspace-root PATH Repository root containing pyproject.toml (default: cwd) + --package NAME Workspace member package name for package-scoped install + --with-cov Also install pytest-cov and add coverage defaults when creating config + --dry-run Print planned commands and file changes without mutating files + --config PATH Explicit YAML config path + --bypassing-all-profiles Ignore global and repo profile files for this run + --bypassing-repo-profile Ignore repo-local profile file for this run + --deleting-repo-profile Delete repo-local profile file before execution + -h, --help Show this help +USAGE +} + +require_cmd() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "error: required command not found: $1" >&2 + exit 1 + fi +} + +fail() { + echo "error: $*" >&2 + exit 1 +} + +trim() { + local value="$1" + value="${value#"${value%%[![:space:]]*}"}" + value="${value%"${value##*[![:space:]]}"}" + printf '%s' "$value" +} + +strip_quotes() { + local value="$1" + if [[ "$value" == \"*\" && "$value" == *\" ]]; then + value="${value:1:${#value}-2}" + elif [[ "$value" == \'*\' && "$value" == *\' ]]; then + value="${value:1:${#value}-2}" + fi + printf '%s' "$value" +} + +bool_to_int() { + local value + value="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')" + case "$value" in + 1|true|yes|on) printf '1\n' ;; + 0|false|no|off) printf '0\n' ;; + *) fail "invalid boolean value '$1'" ;; + esac +} + +apply_config_value() { + local key="$1" + local value="$2" + + case "$key" in + workspace_root) WORKSPACE_ROOT="$value" ;; + package) PACKAGE_NAME="$value" ;; + with_cov) WITH_COV="$(bool_to_int "$value")" ;; + dry_run) DRY_RUN="$(bool_to_int "$value")" ;; + *) fail "unknown config key '$key'" ;; + esac +} + +load_config_file() { + local path="$1" + local required="$2" + + if [[ ! -f "$path" ]]; then + [[ "$required" -eq 1 ]] && fail "config file not found: $path" + return 0 + fi + + local line + local lineno=0 + while IFS= read -r line || [[ -n "$line" ]]; do + lineno=$((lineno + 1)) + line="$(trim "$line")" + [[ -z "$line" || "$line" == \#* ]] && continue + [[ "$line" == *:* ]] || fail "invalid config line at $path:$lineno" + + local key="${line%%:*}" + local value="${line#*:}" + key="$(trim "$key")" + value="${value%%#*}" + value="$(trim "$value")" + value="$(strip_quotes "$value")" + + [[ -n "$key" ]] || fail "empty config key at $path:$lineno" + apply_config_value "$key" "$value" + done < "$path" +} + +run_cmd() { + if [[ "$DRY_RUN" -eq 1 ]]; then + echo "[dry-run] $*" + else + "$@" + fi +} + +append_pytest_config_if_missing() { + local pyproject_path="$1" + local addopts_value="-ra" + + if [[ "$WITH_COV" -eq 1 ]]; then + addopts_value="-ra --cov --cov-report=term-missing" + fi + + if rg -n "^\[tool\.pytest\.ini_options\]" "$pyproject_path" >/dev/null 2>&1; then + echo "info: [tool.pytest.ini_options] already exists in $pyproject_path; leaving config unchanged" + return 0 + fi + + if [[ "$DRY_RUN" -eq 1 ]]; then + echo "[dry-run] append baseline [tool.pytest.ini_options] to $pyproject_path" + return 0 + fi + + cat >>"$pyproject_path" <&2 + usage >&2 + exit 1 + ;; + esac +done + +if [[ "$DELETE_REPO_PROFILE" -eq 1 ]]; then + rm -f "$REPO_PROFILE" +fi + +if [[ "$BYPASS_ALL_PROFILES" -eq 0 ]]; then + load_config_file "$GLOBAL_PROFILE" 0 + if [[ "$BYPASS_REPO_PROFILE" -eq 0 ]]; then + load_config_file "$REPO_PROFILE" 0 + fi +fi + +if [[ -n "$CONFIG_PATH" ]]; then + load_config_file "$CONFIG_PATH" 1 +fi + +set -- "${ORIGINAL_ARGS[@]}" +while [[ $# -gt 0 ]]; do + case "$1" in + --workspace-root) + WORKSPACE_ROOT="$2" + shift 2 + ;; + --package) + PACKAGE_NAME="$2" + shift 2 + ;; + --with-cov) + WITH_COV=1 + shift + ;; + --dry-run) + DRY_RUN=1 + shift + ;; + --config) + shift 2 + ;; + --bypassing-all-profiles|--bypassing-repo-profile|--deleting-repo-profile) + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "error: unknown argument: $1" >&2 + usage >&2 + exit 1 + ;; + esac +done + +require_cmd uv +require_cmd rg + +if [[ ! -d "$WORKSPACE_ROOT" ]]; then + echo "error: workspace root does not exist: $WORKSPACE_ROOT" >&2 + exit 1 +fi + +PYPROJECT_PATH="$WORKSPACE_ROOT/pyproject.toml" +if [[ ! -f "$PYPROJECT_PATH" ]]; then + echo "error: missing pyproject.toml at $PYPROJECT_PATH" >&2 + exit 1 +fi + +cd "$WORKSPACE_ROOT" + +typeset -a deps +if [[ "$WITH_COV" -eq 1 ]]; then + deps=(pytest pytest-cov) +else + deps=(pytest) +fi + +if [[ -n "$PACKAGE_NAME" ]]; then + run_cmd uv add --package "$PACKAGE_NAME" --dev "${deps[@]}" +else + run_cmd uv add --dev "${deps[@]}" +fi + +append_pytest_config_if_missing "$PYPROJECT_PATH" + +echo "info: bootstrap complete" diff --git a/skills/python-testing-workflow/scripts/run_pytest_uv.sh b/skills/python-testing-workflow/scripts/run_pytest_uv.sh new file mode 100755 index 000000000..255e247db --- /dev/null +++ b/skills/python-testing-workflow/scripts/run_pytest_uv.sh @@ -0,0 +1,228 @@ +#!/usr/bin/env zsh +emulate -L zsh +set -euo pipefail + +WORKSPACE_ROOT="$(pwd)" +PACKAGE_NAME="" +TEST_PATH="" + +SKILL_NAME="python-testing-workflow" +SCRIPT_DIR="${0:A:h}" +REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" +GLOBAL_PROFILE="$HOME/.config/gaelic-ghost/python-skills/$SKILL_NAME/customization.yaml" +REPO_PROFILE="$REPO_ROOT/.codex/profiles/$SKILL_NAME/customization.yaml" + +CONFIG_PATH="" +BYPASS_ALL_PROFILES=0 +BYPASS_REPO_PROFILE=0 +DELETE_REPO_PROFILE=0 + +usage() { + cat <<'USAGE' +Usage: run_pytest_uv.sh [--workspace-root PATH] [--package NAME] [--path TEST_PATH] [--config PATH] [-- ] + +Options: + --workspace-root PATH Repository root containing pyproject.toml (default: cwd) + --package NAME Workspace member package name for package-scoped run + --path TEST_PATH Optional test path selector (e.g., tests/unit) + --config PATH Explicit YAML config path + --bypassing-all-profiles Ignore global and repo profile files for this run + --bypassing-repo-profile Ignore repo-local profile file for this run + --deleting-repo-profile Delete repo-local profile file before execution + -- Pass remaining args directly to pytest + -h, --help Show this help +USAGE +} + +require_cmd() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "error: required command not found: $1" >&2 + exit 1 + fi +} + +fail() { + echo "error: $*" >&2 + exit 1 +} + +trim() { + local value="$1" + value="${value#"${value%%[![:space:]]*}"}" + value="${value%"${value##*[![:space:]]}"}" + printf '%s' "$value" +} + +strip_quotes() { + local value="$1" + if [[ "$value" == \"*\" && "$value" == *\" ]]; then + value="${value:1:${#value}-2}" + elif [[ "$value" == \'*\' && "$value" == *\' ]]; then + value="${value:1:${#value}-2}" + fi + printf '%s' "$value" +} + +apply_config_value() { + local key="$1" + local value="$2" + + case "$key" in + workspace_root) WORKSPACE_ROOT="$value" ;; + package) PACKAGE_NAME="$value" ;; + path) TEST_PATH="$value" ;; + *) fail "unknown config key '$key'" ;; + esac +} + +load_config_file() { + local path="$1" + local required="$2" + + if [[ ! -f "$path" ]]; then + [[ "$required" -eq 1 ]] && fail "config file not found: $path" + return 0 + fi + + local line + local lineno=0 + while IFS= read -r line || [[ -n "$line" ]]; do + lineno=$((lineno + 1)) + line="$(trim "$line")" + [[ -z "$line" || "$line" == \#* ]] && continue + [[ "$line" == *:* ]] || fail "invalid config line at $path:$lineno" + + local key="${line%%:*}" + local value="${line#*:}" + key="$(trim "$key")" + value="${value%%#*}" + value="$(trim "$value")" + value="$(strip_quotes "$value")" + + [[ -n "$key" ]] || fail "empty config key at $path:$lineno" + apply_config_value "$key" "$value" + done < "$path" +} + +ORIGINAL_ARGS=("$@") + +while [[ $# -gt 0 ]]; do + case "$1" in + --workspace-root|--package|--path|--config) + [[ $# -ge 2 ]] || fail "$1 requires a value" + if [[ "$1" == "--config" ]]; then + CONFIG_PATH="$2" + fi + shift 2 + ;; + --bypassing-all-profiles) + BYPASS_ALL_PROFILES=1 + shift + ;; + --bypassing-repo-profile) + BYPASS_REPO_PROFILE=1 + shift + ;; + --deleting-repo-profile) + DELETE_REPO_PROFILE=1 + shift + ;; + --) + break + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "error: unknown argument: $1" >&2 + usage >&2 + exit 1 + ;; + esac +done + +if [[ "$DELETE_REPO_PROFILE" -eq 1 ]]; then + rm -f "$REPO_PROFILE" +fi + +if [[ "$BYPASS_ALL_PROFILES" -eq 0 ]]; then + load_config_file "$GLOBAL_PROFILE" 0 + if [[ "$BYPASS_REPO_PROFILE" -eq 0 ]]; then + load_config_file "$REPO_PROFILE" 0 + fi +fi + +if [[ -n "$CONFIG_PATH" ]]; then + load_config_file "$CONFIG_PATH" 1 +fi + +EXTRA_ARGS=() +set -- "${ORIGINAL_ARGS[@]}" +while [[ $# -gt 0 ]]; do + case "$1" in + --workspace-root) + WORKSPACE_ROOT="$2" + shift 2 + ;; + --package) + PACKAGE_NAME="$2" + shift 2 + ;; + --path) + TEST_PATH="$2" + shift 2 + ;; + --config) + shift 2 + ;; + --bypassing-all-profiles|--bypassing-repo-profile|--deleting-repo-profile) + shift + ;; + --) + shift + EXTRA_ARGS=("$@") + break + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "error: unknown argument: $1" >&2 + usage >&2 + exit 1 + ;; + esac +done + +require_cmd uv + +if [[ ! -d "$WORKSPACE_ROOT" ]]; then + echo "error: workspace root does not exist: $WORKSPACE_ROOT" >&2 + exit 1 +fi + +if [[ ! -f "$WORKSPACE_ROOT/pyproject.toml" ]]; then + echo "error: missing pyproject.toml at $WORKSPACE_ROOT/pyproject.toml" >&2 + exit 1 +fi + +cd "$WORKSPACE_ROOT" + +CMD=(uv run) +if [[ -n "$PACKAGE_NAME" ]]; then + CMD+=(--package "$PACKAGE_NAME") +fi +CMD+=(pytest) + +if [[ -n "$TEST_PATH" ]]; then + CMD+=("$TEST_PATH") +fi + +if [[ "${#EXTRA_ARGS[@]}" -gt 0 ]]; then + CMD+=("${EXTRA_ARGS[@]}") +fi + +echo "info: running: ${CMD[*]}" +"${CMD[@]}"