Add @probo/skills multi-agent compliance package

Ship compliance skills and agent plugin wiring for Claude Code,
Codex, OpenCode, and Cursor via Probo MCP (OAuth 2.0). Includes
access-review and missing-signatures workflows, repo-root Git
marketplaces, validation, and npm release CI.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
This commit is contained in:
Cursor Agent
2026-07-10 12:59:49 +00:00
parent a6aabc6dad
commit e3209b74ae
33 changed files with 1701 additions and 1 deletions

View File

@@ -0,0 +1,30 @@
{
"name": "probo",
"interface": {
"displayName": "Probo"
},
"plugins": [
{
"name": "probo",
"description": "Open-source compliance workflows powered by Probo MCP",
"source": {
"source": "local",
"path": "./packages/skills"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity",
"homepage": "https://github.com/getprobo/probo/tree/main/packages/skills",
"repository": "https://github.com/getprobo/probo",
"license": "MIT",
"keywords": [
"probo",
"compliance",
"grc",
"mcp"
]
}
]
}

View File

@@ -0,0 +1,25 @@
{
"name": "probo",
"description": "Probo Claude Code plugins",
"owner": {
"name": "Probo Inc",
"email": "hello@probo.com"
},
"plugins": [
{
"name": "probo",
"description": "Open-source compliance workflows powered by Probo MCP",
"source": "./packages/skills",
"homepage": "https://github.com/getprobo/probo/tree/main/packages/skills",
"repository": "https://github.com/getprobo/probo",
"license": "MIT",
"keywords": [
"probo",
"compliance",
"grc",
"mcp",
"agent-skills"
]
}
]
}

View File

@@ -0,0 +1,98 @@
name: "Release skills"
on:
push:
tags:
- "@probo/skills/v*"
permissions:
contents: "read"
jobs:
publish:
name: "publish"
runs-on: "ubuntu-latest"
permissions:
contents: write
id-token: write
attestations: write
steps:
- uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6
with:
fetch-depth: 0
submodules: recursive
- uses: "actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e" # v6
with:
node-version-file: ".nvmrc"
cache: "npm"
registry-url: "https://registry.npmjs.org"
scope: "@probo"
- run: "npm install -g npm@^11.8.0"
- run: "npm ci"
- name: "Verify package.json version matches tag"
run: |
TAG_VERSION="${GITHUB_REF_NAME##*/v}"
PKG_VERSION="$(node -p "require('./packages/skills/package.json').version")"
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
echo "tag version ($TAG_VERSION) does not match package.json version ($PKG_VERSION)" >&2
exit 1
fi
- run: "npm --workspace @probo/skills run validate"
- uses: "anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610" # v0.24.0
with:
path: ./packages/skills
format: cyclonedx-json
output-file: packages/skills/sbom.json
- uses: "anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2" # v7.4.0
with:
path: ./packages/skills
fail-build: true
severity-cutoff: critical
- name: "Generate checksums for published files"
run: |
cd packages/skills
find .claude-plugin skills commands agents hooks bin -type f 2>/dev/null \
| sort \
| while read -r file; do
echo "$(sha256sum "$file" | head -c 64) $file"
done > checksums.txt
test -s checksums.txt
- run: "npm --workspace @probo/skills publish --access public --dry-run"
- run: "npm --workspace @probo/skills publish --access public"
- uses: "actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e" # v4
with:
subject-path: "packages/skills/**"
sbom-path: "packages/skills/sbom.json"
- uses: "actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32" # v4
with:
subject-path: "packages/skills/**"
- name: "Extract release notes"
run: |
VERSION="${GITHUB_REF_NAME##*/v}"
awk -v ver="$VERSION" '
/^## \[/ { if (found) exit; if ($0 ~ "\\[" ver "\\]") found=1 }
found
' packages/skills/CHANGELOG.md > release-notes.md
- name: "Create GitHub release"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PRERELEASE_FLAG=""
if echo "${GITHUB_REF_NAME}" | grep -qE '(alpha|beta|rc)'; then
PRERELEASE_FLAG="--prerelease"
fi
gh release delete "${GITHUB_REF_NAME}" --yes 2>/dev/null || true
gh release create "${GITHUB_REF_NAME}" \
--title "${GITHUB_REF_NAME}" \
--notes-file release-notes.md \
$PRERELEASE_FLAG \
packages/skills/sbom.json packages/skills/checksums.txt
- uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7
with:
name: "skills-sbom"
path: |
packages/skills/sbom.json
packages/skills/checksums.txt
retention-days: 30

View File

@@ -41,3 +41,4 @@ Detailed guides for specific subsystems live in `contrib/claude/`:
- [`contrib/claude/release/README.md`](contrib/claude/release/README.md) — Release process (per-track version bump, changelog, tag, push) - [`contrib/claude/release/README.md`](contrib/claude/release/README.md) — Release process (per-track version bump, changelog, tag, push)
- [`contrib/claude/sandbox.md`](contrib/claude/sandbox.md) — Lima sandbox environments (create, manage, access services) - [`contrib/claude/sandbox.md`](contrib/claude/sandbox.md) — Lima sandbox environments (create, manage, access services)
- [`contrib/claude/n8n.md`](contrib/claude/n8n.md) — n8n community node (resources, operations, GraphQL helpers) - [`contrib/claude/n8n.md`](contrib/claude/n8n.md) — n8n community node (resources, operations, GraphQL helpers)
- [`contrib/claude/skills.md`](contrib/claude/skills.md) — Agent skills package (`@probo/skills`, compliance workflows, Probo MCP)

View File

@@ -1,6 +1,6 @@
# Release # Release
The repository ships eight independently-versioned tracks. Each has its own The repository ships nine independently-versioned tracks. Each has its own
version source, its own `CHANGELOG.md`, its own tag pattern, and its own version source, its own `CHANGELOG.md`, its own tag pattern, and its own
release workflow. Cutting a release means: bump the version, write a release workflow. Cutting a release means: bump the version, write a
changelog entry, commit, tag, push. changelog entry, commit, tag, push.
@@ -14,6 +14,7 @@ changelog entry, commit, tag, push.
| `probo-agent` | `probo-agent/v*` | [probo-agent.md](./probo-agent.md) | | `probo-agent` | `probo-agent/v*` | [probo-agent.md](./probo-agent.md) |
| `@probo/n8n-nodes-probo` | `@probo/n8n-nodes-probo/v*` | [n8n-nodes-probo.md](./n8n-nodes-probo.md) | | `@probo/n8n-nodes-probo` | `@probo/n8n-nodes-probo/v*` | [n8n-nodes-probo.md](./n8n-nodes-probo.md) |
| `@probo/cookie-banner` | `@probo/cookie-banner/v*` | [cookie-banner.md](./cookie-banner.md) | | `@probo/cookie-banner` | `@probo/cookie-banner/v*` | [cookie-banner.md](./cookie-banner.md) |
| `@probo/skills` | `@probo/skills/v*` | [skills.md](./skills.md) |
| Helm chart (`probo`) | `helm/v*` | [helm.md](./helm.md) | | Helm chart (`probo`) | `helm/v*` | [helm.md](./helm.md) |
When the user asks for a release **without specifying a track**, follow When the user asks for a release **without specifying a track**, follow
@@ -76,6 +77,10 @@ git log $(git describe --tags --abbrev=0 --match='@probo/n8n-nodes-probo/v*')..H
git log $(git describe --tags --abbrev=0 --match='@probo/cookie-banner/v*')..HEAD --oneline \ git log $(git describe --tags --abbrev=0 --match='@probo/cookie-banner/v*')..HEAD --oneline \
-- packages/cookie-banner -- packages/cookie-banner
# @probo/skills
git log $(git describe --tags --abbrev=0 --match='@probo/skills/v*')..HEAD --oneline \
-- packages/skills
# helm chart # helm chart
git log $(git describe --tags --abbrev=0 --match='helm/v*')..HEAD --oneline \ git log $(git describe --tags --abbrev=0 --match='helm/v*')..HEAD --oneline \
-- contrib/helm -- contrib/helm

View File

@@ -0,0 +1,31 @@
# Release `@probo/skills`
After confirming commits below, follow the
[common steps](./README.md#3-common-steps-every-track).
## Track facts
- **Tag pattern**: `@probo/skills/v*`
- **Version source**: `packages/skills/package.json`
- **Version bump**: `npm --workspace @probo/skills version <X.Y.Z> --no-git-tag-version`
- **Validate**: `npm --workspace @probo/skills run validate`
- **Changelog**: `packages/skills/CHANGELOG.md`
- **Files to stage**: `packages/skills/package.json`,
`packages/skills/CHANGELOG.md`, `package-lock.json`
- **Workflow**: `.github/workflows/release-npm-skills.yaml`
- **Path filter**: `packages/skills`
## Detect commits
```shell
git log $(git describe --tags --abbrev=0 --match='@probo/skills/v*')..HEAD --oneline \
-- packages/skills
```
If empty or non-user-facing only, do not release this track.
## Notes
There is no build step. Run `validate` after the version bump to catch manifest
or structural errors before tagging. CI runs the same validation, publishes to
npm with provenance + SBOM, and creates a GitHub Release.

128
contrib/claude/skills.md Normal file
View File

@@ -0,0 +1,128 @@
# Agent skills (`packages/skills`)
npm package [`@probo/skills`](../../packages/skills) ships multi-agent
compliance skills and agent plugin wiring powered by the Probo MCP API.
Compatible with **Claude Code**, **Codex**, **OpenCode**, and **Cursor** (via
MCP + skills). See [`COMPATIBILITY.md`](../../packages/skills/COMPATIBILITY.md).
## What this package ships
A **skills package** bundling:
| Component | Role |
| --- | --- |
| `skills/` | Agent Skillscompatible workflow instructions |
| `.mcp.json` | Connects agents to Probo (`/mcp/v1`, OAuth 2.0) |
| `commands/` | Explicit slash commands (e.g. `access-review`, Claude Code only) |
| `agents/` | Optional specialized subagents |
| `hooks/` | Optional event automation |
Individual capabilities are namespaced under `probo`:
- Skills: `/probo:<skill-name>` (e.g. `/probo:open-source-compliance`,
`/probo:missing-signatures`, `/probo:access-review`)
- Commands: `/probo:<command-name>` (e.g. `/probo:access-review`,
`/probo:missing-signatures`)
Published to npm as `@probo/skills`. Agent-specific manifests (`.claude-plugin/`,
`.codex-plugin/`) ship inside the same package.
## Directory structure
```
.claude-plugin/marketplace.json # repo root — Claude catalog for getprobo/probo
.agents/plugins/marketplace.json # repo root — Codex catalog for getprobo/probo
packages/skills/
.claude-plugin/
plugin.json # Claude Code manifest (required)
marketplace.json # Claude marketplace catalog (npm)
.agents/plugins/
marketplace.json # Codex catalog when marketplace root is the package
.codex-plugin/
plugin.json # Codex manifest
.mcp.json # Probo MCP server wiring
skills/
<skill-name>/
SKILL.md
references/
commands/
agents/
hooks/
scripts/validate.mjs
package.json
CHANGELOG.md
```
Only `plugin.json` belongs inside `.claude-plugin/`. All other directories
must sit at the package root.
## plugin.json rules
Claude Code validates the manifest strictly. Common pitfalls:
| Field | Expected type | Notes |
| --- | --- | --- |
| `name` | string | Skill namespace (`probo``/probo:open-source-compliance`) |
| `repository` | string URL | **Not** the npm-style `{ type, url }` object |
| `bugs` | string URL | **Not** the npm-style `{ url }` object |
| `version` | string | Bump on every release when using explicit versioning |
Run `npm --workspace @probo/skills run validate` before publishing.
## Probo MCP configuration
The package `.mcp.json` expects one environment variable:
- `PROBO_BASE_URL` — instance root URL
Authentication is OAuth 2.0 only. Users complete sign-in via `/mcp` or
`claude mcp login probo`. Do not document API keys or bearer tokens in the
plugin config — a pre-set `Authorization` header prevents Claude Code from
starting the OAuth flow.
## Adding a skill
1. Create `skills/<name>/SKILL.md` with YAML frontmatter (`name`, `description`).
2. Add `references/` for detailed workflow docs loaded on demand.
3. Validate and test:
```bash
npm --workspace @probo/skills run validate
claude --plugin-dir ./packages/skills
/probo:<name>
```
4. Update `packages/skills/CHANGELOG.md` under `## Unreleased`.
Skills must be self-contained — npm installs do not include `contrib/claude/`
from the monorepo.
## Adding a command
Use commands for explicit, user-invoked workflows on Claude Code only. Pair a
thin `commands/<name>.md` with a shared `skills/<name>/SKILL.md` so Codex and
OpenCode load the same workflow. Reference docs live under
`skills/<name>/references/` using paths relative to the skill directory (not
`${CLAUDE_PLUGIN_ROOT}`).
1. Create `commands/<name>.md` with frontmatter (`description`,
`argument-hint`, `disable-model-invocation: true` when writes are involved).
2. Add reference docs under `skills/<name>/references/`.
3. Register paths in `scripts/validate.mjs`.
4. Test: `/probo:<name> <args>` after `claude --plugin-dir ./packages/skills`.
## Distribution
Published to npm as `@probo/skills`. Claude marketplace entry:
```json
{
"source": {
"source": "npm",
"package": "@probo/skills"
}
}
```
Release process: [`contrib/claude/release/skills.md`](release/skills.md).

View File

@@ -17,6 +17,7 @@ export default defineConfig([
"pkg/**", "pkg/**",
"packages/coredata/**", "packages/coredata/**",
"packages/cookie-banner/**", "packages/cookie-banner/**",
"packages/skills/**",
"packages/emails/**", "packages/emails/**",
"packages/eslint-relay-plugin-types/**", "packages/eslint-relay-plugin-types/**",
"packages/helpers/**", "packages/helpers/**",

10
package-lock.json generated
View File

@@ -4820,6 +4820,10 @@
"resolved": "packages/routes", "resolved": "packages/routes",
"link": true "link": true
}, },
"node_modules/@probo/skills": {
"resolved": "packages/skills",
"link": true
},
"node_modules/@probo/trust": { "node_modules/@probo/trust": {
"resolved": "apps/trust", "resolved": "apps/trust",
"link": true "link": true
@@ -19347,6 +19351,7 @@
"os": [ "os": [
"darwin" "darwin"
], ],
"peer": true,
"engines": { "engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0" "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
} }
@@ -21151,6 +21156,11 @@
"relay-runtime": "^21.0.1" "relay-runtime": "^21.0.1"
} }
}, },
"packages/skills": {
"name": "@probo/skills",
"version": "0.1.0",
"license": "MIT"
},
"packages/tsconfig": { "packages/tsconfig": {
"name": "@probo/tsconfig", "name": "@probo/tsconfig",
"version": "0.0.1", "version": "0.0.1",

View File

@@ -0,0 +1,30 @@
{
"name": "probo",
"interface": {
"displayName": "Probo"
},
"plugins": [
{
"name": "probo",
"description": "Open-source compliance workflows powered by Probo MCP",
"source": {
"source": "local",
"path": "./"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity",
"homepage": "https://github.com/getprobo/probo/tree/main/packages/skills",
"repository": "https://github.com/getprobo/probo",
"license": "MIT",
"keywords": [
"probo",
"compliance",
"grc",
"mcp"
]
}
]
}

View File

@@ -0,0 +1,28 @@
{
"name": "probo",
"description": "Probo Claude Code plugins",
"owner": {
"name": "Probo Inc",
"email": "hello@probo.com"
},
"plugins": [
{
"name": "probo",
"description": "Open-source compliance workflows powered by Probo MCP",
"source": {
"source": "npm",
"package": "@probo/skills"
},
"homepage": "https://github.com/getprobo/probo/tree/main/packages/skills",
"repository": "https://github.com/getprobo/probo",
"license": "MIT",
"keywords": [
"probo",
"compliance",
"grc",
"mcp",
"agent-skills"
]
}
]
}

View File

@@ -0,0 +1,21 @@
{
"name": "probo",
"version": "0.1.0",
"description": "Open-source compliance workflows powered by Probo MCP (Claude Code, Codex, OpenCode)",
"author": {
"name": "Probo Inc",
"email": "hello@probo.com"
},
"homepage": "https://github.com/getprobo/probo/tree/main/packages/skills",
"repository": "https://github.com/getprobo/probo",
"license": "MIT",
"keywords": [
"probo",
"compliance",
"grc",
"mcp",
"open-source"
],
"skills": "./skills/",
"mcpServers": "./.mcp.json"
}

View File

@@ -0,0 +1,21 @@
{
"name": "probo",
"version": "0.1.0",
"description": "Open-source compliance workflows powered by Probo MCP (Codex, OpenCode, Claude Code)",
"author": {
"name": "Probo Inc",
"email": "hello@probo.com"
},
"homepage": "https://github.com/getprobo/probo/tree/main/packages/skills",
"repository": "https://github.com/getprobo/probo",
"license": "MIT",
"keywords": [
"probo",
"compliance",
"grc",
"mcp",
"open-source"
],
"skills": "./skills/",
"mcpServers": "./.mcp.json"
}

View File

@@ -0,0 +1,8 @@
{
"mcpServers": {
"probo": {
"type": "http",
"url": "${PROBO_BASE_URL}/mcp/v1"
}
}
}

View File

@@ -0,0 +1,29 @@
# Changelog
All notable changes to the `@probo/skills` package will be documented in
this file.
## Unreleased
### Added
- `@probo/skills` npm package with multi-agent manifests (`.claude-plugin/`,
`.codex-plugin/`, `.agents/`) and Probo MCP wiring via `.mcp.json`
(`PROBO_BASE_URL`, OAuth 2.0 sign-in)
- Skills: `open-source-compliance`, `access-review`, `missing-signatures`
- Commands: `access-review`, `missing-signatures` (Claude Code slash commands
delegating to shared skills)
- Portable relative `references/` paths in skill bodies (no
`${CLAUDE_PLUGIN_ROOT}`)
- Resumable session notes for `access-review` and `missing-signatures`
- Repo-root marketplace catalogs for Git installs (`getprobo/probo`):
`.claude-plugin/marketplace.json` (Claude Code) and
`.agents/plugins/marketplace.json` (Codex)
- Package-local marketplace catalogs under `packages/skills/`
- `COMPATIBILITY.md`, validation script, and release workflow
(`release-npm-skills.yaml`, tag `@probo/skills/v*`)
### Changed
- Package published as `@probo/skills` in `packages/skills/` (multi-agent
scope, not Claude-specific)

View File

@@ -0,0 +1,154 @@
# Multi-agent compatibility
`@probo/skills` targets **Claude Code**, **Codex**, **OpenCode**, and
other MCP-capable agents (including **Cursor**). The portable core is Probo
MCP plus Agent Skillscompatible `SKILL.md` files.
## What works where
| Component | Claude Code | Codex | OpenCode | Cursor |
| --- | --- | --- | --- | --- |
| Probo MCP (OAuth) | ✅ Plugin `.mcp.json` | ✅ `.codex-plugin` + `.mcp.json` | ✅ Manual MCP config | ✅ IDE MCP settings |
| Skills (`SKILL.md`) | ✅ `skills/` | ✅ `skills/` via `.codex-plugin` | ✅ `.opencode/skills/` or `.claude/skills/` | ✅ Copy/symlink to `.cursor/skills/` |
| Commands | ✅ `commands/``/probo:…` | ⚠️ Use skills instead | ⚠️ Native `skill` tool | ❌ Use skill or rules |
| Plugin manifest | `.claude-plugin/` | `.codex-plugin/` | Discovery paths (no manifest) | No native manifest |
| Marketplace catalog | `.claude-plugin/marketplace.json` (repo root or package) | `.agents/plugins/marketplace.json` (repo root or package) | — | — |
## Probo MCP (all agents)
Set the instance URL:
```bash
export PROBO_BASE_URL="https://your-probo-instance.example.com"
```
Endpoint: `${PROBO_BASE_URL}/mcp/v1` (HTTP, OAuth 2.0). Do not configure a
static bearer token — OAuth discovery uses
`/.well-known/oauth-protected-resource`.
### Claude Code
**From the monorepo or GitHub** (repo-root catalog at
`.claude-plugin/marketplace.json`):
```bash
claude plugin marketplace add getprobo/probo
# or, from a local clone:
claude plugin marketplace add .
claude plugin install probo@probo
claude mcp login probo # or /mcp in session
/probo:access-review Q3 GitHub review
```
**From the package directory** (catalog resolves `@probo/skills` from npm):
```bash
claude plugin marketplace add ./packages/skills/.claude-plugin
claude plugin install probo@probo
claude mcp login probo
```
Or install the plugin directory directly:
```bash
claude --plugin-dir ./packages/skills
```
### Codex
**From the monorepo or GitHub** (repo-root catalog at
`.agents/plugins/marketplace.json`):
```bash
codex plugin marketplace add getprobo/probo
# or, from a local clone:
codex plugin marketplace add .
codex plugin install probo@probo
codex mcp login probo
```
**From the package directory** (catalog at
`packages/skills/.agents/plugins/marketplace.json`):
```bash
codex plugin marketplace add ./packages/skills
codex plugin install probo@probo
codex mcp login probo
```
Or install the plugin directory directly:
```bash
codex plugin install ./packages/skills
codex mcp login probo
```
Skills load from `./skills/` via `.codex-plugin/plugin.json`. The repo-root
marketplace `source.path` is `./packages/skills`; the package-level
catalog uses `./` (plugin package root).
### OpenCode
OpenCode discovers skills at `.opencode/skills/`, `.claude/skills/`, and
`~/.config/opencode/skills/`. Options:
**Option A — symlink from this package:**
```bash
mkdir -p .opencode/skills
ln -s ../../packages/skills/skills/access-review .opencode/skills/access-review
ln -s ../../packages/skills/skills/open-source-compliance .opencode/skills/open-source-compliance
```
**Option B — Claude Code bridge:** install
[`opencode-claude-code-bridge`](https://www.npmjs.com/package/opencode-claude-code-bridge)
to import Claude plugins and MCP configs into OpenCode.
Configure Probo MCP in `opencode.json` or global OpenCode MCP settings, then
authenticate. Invoke via the native `skill` tool (`access-review`).
### Cursor
1. Add Probo MCP in Cursor settings (HTTP URL: `${PROBO_BASE_URL}/mcp/v1`,
OAuth).
2. Copy or symlink skills into `.cursor/skills/`:
```bash
mkdir -p .cursor/skills
cp -r packages/skills/skills/access-review .cursor/skills/
```
Reference the skill in chat or add a Cursor rule pointing at the skill.
## Portable vs agent-specific paths
| Path | Portable? |
| --- | --- |
| `skills/<name>/SKILL.md` | ✅ Agent Skills standard |
| `skills/<name>/references/*.md` | ✅ Relative to skill directory |
| `.mcp.json` with `${PROBO_BASE_URL}` | ✅ Standard env var |
| `${CLAUDE_PLUGIN_ROOT}` | ❌ Claude Code only — avoid in skill bodies |
| `commands/*.md` | Claude Code slash commands only |
Skill bodies use **relative** `references/` paths so they work once the skill
directory is discovered, regardless of which agent loads it.
## npm package layout
```
@probo/skills/
.claude-plugin/plugin.json # Claude Code manifest
.claude-plugin/marketplace.json # Claude marketplace (npm)
.codex-plugin/plugin.json # Codex manifest
.agents/plugins/marketplace.json # Codex marketplace (package-local)
.mcp.json # Shared MCP wiring
skills/ # Shared skills (all agents)
commands/ # Claude Code commands only
```
Repo root (monorepo / `getprobo/probo` Git installs):
```
.claude-plugin/marketplace.json # Claude marketplace → packages/skills
.agents/plugins/marketplace.json # Codex marketplace → packages/skills
```

98
packages/skills/README.md Normal file
View File

@@ -0,0 +1,98 @@
# @probo/skills
Multi-agent compliance skills for open-source GRC workflows. Ships Agent
Skillscompatible instructions and wires agents to the [Probo MCP
API](https://github.com/getprobo/probo/tree/main/pkg/server/api/mcp/v1) via
OAuth 2.0.
**Supported agents:** Claude Code, Codex, OpenCode, Cursor (MCP + skills).
Marketplace catalogs: `.claude-plugin/marketplace.json` at the repo root or
under `packages/skills/` (Claude Code), `.agents/plugins/marketplace.json` at
the repo root or under `packages/skills/` (Codex). See
[COMPATIBILITY.md](./COMPATIBILITY.md).
## Install
### From GitHub or npm
**From GitHub** (repo-root catalog at `.claude-plugin/marketplace.json`):
```bash
claude plugin marketplace add getprobo/probo
# or, from a local clone:
claude plugin marketplace add .
claude plugin install probo@probo
```
**From the package directory** (catalog at
`packages/skills/.claude-plugin/marketplace.json`, resolves `@probo/skills`
from npm):
```bash
claude plugin marketplace add ./packages/skills/.claude-plugin
claude plugin install probo@probo
```
When consuming the published package, the package-level marketplace entry
resolves `@probo/skills` from npm (see
`packages/skills/.claude-plugin/marketplace.json`).
### Configure Probo MCP
Set your Probo instance URL before starting Claude Code:
```bash
export PROBO_BASE_URL="https://your-probo-instance.example.com"
```
The plugin `.mcp.json` connects to `${PROBO_BASE_URL}/mcp/v1`. Probo MCP
authenticates with **OAuth 2.0** — no API token or bearer header is required in
the plugin config. On first use, sign in from Claude Code:
```text
/mcp
```
Or from your shell:
```bash
claude mcp login probo
```
Claude Code discovers Probo's authorization server via
`/.well-known/oauth-protected-resource` and stores tokens securely.
### Local development
```bash
claude --plugin-dir ./packages/skills
```
## What's included
| Component | Location | Purpose |
| --- | --- | --- |
| MCP | `.mcp.json` | Probo API connection |
| Skills | `skills/` | Compliance workflows |
| Commands | `commands/` | `access-review`, `missing-signatures` — semi-auto workflows |
| Agents | `agents/` | Reserved |
| Hooks | `hooks/` | Reserved |
Skills: `/probo:<skill-name>` (e.g. `/probo:open-source-compliance`, `/probo:missing-signatures`).
Commands: `/probo:<command-name>` (e.g. `/probo:access-review`, `/probo:missing-signatures`).
## Adding content
See [`contrib/claude/skills.md`](../../contrib/claude/skills.md).
```bash
npm --workspace @probo/skills run validate
claude --plugin-dir ./packages/skills
```
## Release
Published to npm as `@probo/skills`. See
[`contrib/claude/release/skills.md`](../../contrib/claude/release/skills.md).

View File

View File

@@ -0,0 +1,17 @@
---
description: Run a semi-automated access review on a Probo campaign (Claude Code slash command).
argument-hint: [campaign name or id]
disable-model-invocation: true
---
# Access review command
Execute the `access-review` skill for campaign `$ARGUMENTS`.
1. Load `skills/access-review/SKILL.md` from the plugin package root.
2. Load reference docs from `skills/access-review/references/` as directed by
the skill.
3. Follow the skill workflow exactly.
Do not duplicate skill logic here — the skill is the canonical workflow shared
with Codex and OpenCode.

View File

@@ -0,0 +1,17 @@
---
description: Report missing document signatures and pending quorum approvals per person (Claude Code slash command).
argument-hint: [organization name or id]
disable-model-invocation: true
---
# Missing signatures command
Execute the `missing-signatures` skill for organization `$ARGUMENTS`.
1. Load `skills/missing-signatures/SKILL.md` from the plugin package root.
2. Load reference docs from `skills/missing-signatures/references/` as directed
by the skill.
3. Follow the skill workflow exactly.
Do not duplicate skill logic here — the skill is the canonical workflow shared
with Codex and OpenCode.

View File

View File

@@ -0,0 +1,52 @@
{
"name": "@probo/skills",
"version": "0.1.0",
"description": "Multi-agent compliance skills for open-source GRC (Claude Code, Codex, OpenCode) powered by Probo MCP",
"private": false,
"scripts": {
"validate": "node scripts/validate.mjs",
"release": "npm run validate && npm publish --access public",
"prepublishOnly": "npm run validate"
},
"author": {
"name": "Probo Inc",
"email": "hello@probo.com"
},
"files": [
".claude-plugin",
".codex-plugin",
".agents",
"skills",
"commands",
"agents",
"hooks",
"bin",
".mcp.json",
"README.md",
"COMPATIBILITY.md"
],
"keywords": [
"claude-code",
"agent-skills",
"codex",
"opencode",
"probo",
"compliance",
"grc",
"mcp",
"open-source"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/getprobo/probo.git",
"directory": "packages/skills"
},
"bugs": {
"url": "https://github.com/getprobo/probo/issues"
},
"homepage": "https://github.com/getprobo/probo/tree/main/packages/skills#readme",
"publishConfig": {
"access": "public"
}
}

View File

@@ -0,0 +1,105 @@
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
import { existsSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
const requiredPaths = [
".claude-plugin/plugin.json",
".codex-plugin/plugin.json",
".agents/plugins/marketplace.json",
".mcp.json",
"commands/access-review.md",
"commands/missing-signatures.md",
"skills/access-review/SKILL.md",
"skills/missing-signatures/SKILL.md",
"skills/open-source-compliance/SKILL.md",
"skills/access-review/references/mcp-tools.md",
"skills/access-review/references/decision-rubric.md",
"skills/access-review/references/notes-format.md",
"skills/missing-signatures/references/mcp-tools.md",
"skills/missing-signatures/references/report-format.md",
"skills/missing-signatures/references/notes-format.md",
"COMPATIBILITY.md",
];
let failed = false;
for (const relativePath of requiredPaths) {
const absolutePath = join(root, relativePath);
if (!existsSync(absolutePath)) {
console.error(`missing required file: ${relativePath}`);
failed = true;
}
}
const manifestPath = join(root, ".claude-plugin/plugin.json");
const codexManifestPath = join(root, ".codex-plugin/plugin.json");
for (const [label, path] of [
["plugin.json", manifestPath],
[".codex-plugin/plugin.json", codexManifestPath],
]) {
if (!existsSync(path)) {
continue;
}
try {
const manifest = JSON.parse(readFileSync(path, "utf8"));
if (typeof manifest.name !== "string" || manifest.name.length === 0) {
console.error(`${label}: name must be a non-empty string`);
failed = true;
}
if (manifest.repository != null && typeof manifest.repository !== "string") {
console.error(
`${label}: repository must be a string URL, not an object`,
);
failed = true;
}
if (manifest.bugs != null && typeof manifest.bugs !== "string") {
console.error(`${label}: bugs must be a string URL, not an object`);
failed = true;
}
} catch (error) {
console.error(`${label} is not valid JSON: ${error.message}`);
failed = true;
}
}
const mcpPath = join(root, ".mcp.json");
if (existsSync(mcpPath)) {
try {
const mcpConfig = JSON.parse(readFileSync(mcpPath, "utf8"));
const servers = mcpConfig.mcpServers ?? {};
for (const [name, config] of Object.entries(servers)) {
if (config?.headers?.Authorization != null) {
console.error(
`.mcp.json: ${name} must use OAuth 2.0, not headers.Authorization`,
);
failed = true;
}
}
} catch (error) {
console.error(`.mcp.json is not valid JSON: ${error.message}`);
failed = true;
}
}
if (failed) {
process.exit(1);
}
console.log("@probo/skills validation passed");

View File

@@ -0,0 +1,82 @@
---
name: access-review
description: Run a semi-automated Probo access review campaign. Use when the user wants to review access entries, decide approve/revoke/escalate, or resume an in-progress campaign with MCP and .probo/access-reviews/ notes.
compatibility: Requires Probo MCP (OAuth 2.0) and file write access for .probo/access-reviews/
---
# Access review
Run a **semi-automated** access review for campaign `$ARGUMENTS` (or ask the
user for the campaign name). Review entries only — do not create, start,
cancel, or close campaigns.
Before executing, read these files **relative to this skill directory**:
- `references/mcp-tools.md` — MCP tool names, inputs, pagination
- `references/decision-rubric.md` — semi-auto decision rules
- `references/notes-format.md` — working memory file schema
## Preconditions
1. Probo MCP must be connected. If tools fail with auth errors, stop and tell
the user to complete OAuth sign-in for the Probo MCP server in their agent
(Claude Code: `/mcp` or `claude mcp login probo`; Codex: `codex mcp login
probo`; OpenCode/Cursor: configure MCP in settings then authenticate).
2. Resolve the campaign from `$ARGUMENTS` (name match or GID). If ambiguous,
list `listAccessReviewCampaigns` results and ask the user to pick one.
3. Campaign `status` must be `IN_PROGRESS` or `PENDING_ACTIONS`. Stop with a
clear message for `DRAFT`, `COMPLETED`, or `CANCELLED`.
## Working notes file
Create or resume `.probo/access-reviews/<campaign-slug>.md` per
`references/notes-format.md`. Create `.probo/access-reviews/` if missing.
## Workflow
### 1. Orient
- Call `getAccessReviewStatistics` for the campaign.
- Summarize totals and pending count for the user.
- If no pending entries, report completion and stop.
### 2. Fetch batch
- Call `listAccessEntries` with `campaign_id`, `filter.decision: PENDING`,
`size: 50`.
- Use `last_cursor` from the notes file when resuming.
### 3. Classify each entry
Apply `references/decision-rubric.md`:
| Class | Action |
| --- | --- |
| **Auto** | Queue for `recordAccessReviewEntryDecisions` |
| **Ambiguous** | Present to user; do not write yet |
| **Skip** | Log in notes only |
Append each auto decision to the notes file before writing.
### 4. Write auto decisions
- Batch via `recordAccessReviewEntryDecisions` when possible.
- Non-`APPROVED` decisions **must** include `decision_note`.
- On MCP error, stop and do not advance `last_cursor`.
### 5. Present ambiguous entries
Show email, roles, flags, proposed decision, rationale. Record only after
explicit user confirmation.
### 6. Checkpoint
Update notes: `last_cursor`, session log, `updated_at`. Ask to continue if
`next_cursor` is set.
## Hard rules
- Never call `closeAccessReviewCampaign` or campaign setup mutations unless
the user explicitly requests setup work outside this skill.
- Never invent entry IDs or decisions — use MCP responses only.
- Never record non-`APPROVED` without `decision_note`.

View File

@@ -0,0 +1,60 @@
# Semi-auto decision rubric
Classify each `PENDING` entry before writing to Probo.
## Auto — record without asking
Apply the **first matching rule** (top to bottom). Always set `decision_note`
for non-`APPROVED` decisions.
| Condition | Decision | decision_note template |
| --- | --- | --- |
| `TERMINATED_USER` flag | `REVOKE` | Terminated user — access no longer required |
| `CONTRACTOR_EXPIRED` flag | `REVOKE` | Contractor engagement ended |
| `active === false` and no `NEW` tag | `REVOKE` | Account inactive at source |
| `ORPHANED` flag and `active === false` | `REVOKE` | Orphaned inactive account |
| `ORPHANED` flag only, `active !== false` | `ESCALATE` | Orphaned account still active — needs owner |
| `SHARED_ACCOUNT` flag | `ESCALATE` | Shared account — assign individual owner |
| `SOD_CONFLICT` flag | `ESCALATE` | Segregation of duties conflict |
| `PRIVILEGED_ACCESS` or `ROLE_CREEP` flag | `ESCALATE` | Privileged access requires explicit approval |
| `is_admin === true` and (`DORMANT` flag or last_login very stale) | `ESCALATE` | Admin access dormant — confirm business need |
| `account_type === SERVICE_ACCOUNT`, active, no danger flags | `APPROVED` | Service account with expected access |
| Active user, no flags (or only `NONE`), not admin, `incremental_tag !== NEW` | `APPROVED` | Routine access reaffirmed |
"Very stale" last_login: no login in 90+ days when `last_login` is present.
## Ambiguous — show user, do not write
| Condition | Suggested default | Why ambiguous |
| --- | --- | --- |
| `incremental_tag === NEW` | `ESCALATE` | New access since last campaign |
| `NO_BUSINESS_JUSTIFICATION` flag | `ESCALATE` or `REVOKE` | Needs human judgment |
| `OUT_OF_DEPARTMENT` flag | `ESCALATE` | Role/department mismatch |
| `EXCESSIVE` or `ROLE_MISMATCH` flag | `ESCALATE` | Role change needs context |
| `is_admin === true` without dormant signals | `ESCALATE` | Admin approvals need explicit sign-off |
| `mfa_status === DISABLED` and (`is_admin` or privileged flags) | `ESCALATE` | MFA gap on sensitive access |
| `auth_method === API_KEY` or `PASSWORD` on production-like roles | `ESCALATE` | Non-SSO auth on sensitive access |
| Multiple conflicting flags | `ESCALATE` | Rubric rules disagree |
| `active === null` with revoke-leaning flags | `ESCALATE` | Unknown activity state |
Present the suggested decision; wait for explicit user confirmation.
## Flagging before decision
Do not auto-flag unless the user asks. When reviewing ambiguous entries, you
may **suggest** `flagAccessReviewEntry` if Probo shows `NONE` but signals are
obvious (e.g. admin + 180d no login → suggest `DORMANT`).
## Decision notes
- `APPROVED``decision_note` optional
- `REVOKE`, `DEFER`, `ESCALATE``decision_note` **required** (MCP rejects empty)
- Keep notes short, factual, auditable. Reference flags and activity signals.
## DEFER vs ESCALATE
- `ESCALATE` — needs another reviewer or manager (security, HR, app owner)
- `DEFER` — modify access (role change, downgrade) before final approval; use
when the user indicates access should change rather than fully revoke
Default to `ESCALATE` when unsure.

View File

@@ -0,0 +1,93 @@
# Access review MCP tools
All tools are on the Probo MCP server (`probo`). Read each tool schema before
calling.
## Read
### `listAccessReviewCampaigns`
List campaigns for an organization. Use to resolve `$ARGUMENTS` to a campaign
when the user provides a name instead of a GID.
Required: `organization_id`
### `listAccessEntries`
List entries for a campaign. Primary data source for this command.
| Field | Usage |
| --- | --- |
| `campaign_id` | Campaign GID |
| `filter.decision` | Use `PENDING` for review batches |
| `filter.flag` | Optional — focus on a flag (e.g. `TERMINATED_USER`) |
| `filter.incremental_tag` | Optional — `NEW`, `REMOVED`, `UNCHANGED` |
| `filter.is_admin` | Optional boolean |
| `filter.active` | Optional boolean |
| `size` | Page size; use `50` per batch |
| `cursor` | Resume pagination; store in notes file as `last_cursor` |
Returns `entries[]` and `next_cursor`.
### `getAccessReviewStatistics`
Required: `campaign_id`
Returns `statistics` with `total_count`, `decision_counts`, `flag_counts`,
`incremental_tag_counts`. Call at the start of each run and after large batches.
## Write (semi-auto command)
### `recordAccessReviewEntryDecisions`
Preferred for auto batch. Input `decisions[]` with:
- `access_review_entry_id` (required)
- `decision``APPROVED`, `REVOKE`, `DEFER`, `ESCALATE` (not `PENDING`)
- `decision_note` — required for non-`APPROVED`
### `recordAccessReviewEntryDecision`
Use for single entries after user confirms an ambiguous case.
### `flagAccessReviewEntry`
Optional when the user agrees a flag is missing. Input:
- `access_review_entry_id`
- `flags[]` — see rubric for valid values
- `flag_reasons[]` — optional strings
## Out of scope for this command
Do not call unless the user explicitly asks for campaign setup:
- `closeAccessReviewCampaign`
- `cancelAccessReviewCampaign`
- `startAccessReviewCampaign`
- `createAccessReviewCampaign`
- `createAccessReviewSource` / source mutations
## Entry fields (review signals)
| Field | Review use |
| --- | --- |
| `email`, `full_name` | Identity |
| `roles`, `job_title` | Access level |
| `is_admin` | Heightened scrutiny |
| `active` | `false` often supports revoke |
| `mfa_status` | `DISABLED` on privileged access → escalate |
| `auth_method` | `API_KEY`, `SERVICE_ACCOUNT` context |
| `account_type` | `SERVICE_ACCOUNT` vs `USER` |
| `last_login` | Dormancy signal |
| `incremental_tag` | `NEW` needs extra scrutiny |
| `flags`, `flag_reasons` | Primary risk signals |
| `decision` | Target `PENDING` entries only |
## Pagination and resume
1. Read `last_cursor` from the notes file.
2. Pass it to `listAccessEntries` to continue where the last batch stopped.
3. Write the new `next_cursor` back after each successful batch.
4. When `next_cursor` is null/empty, the pending page is exhausted — refresh
statistics to confirm remaining `PENDING` count.

View File

@@ -0,0 +1,59 @@
# Access review notes file
Path: `.probo/access-reviews/<campaign-slug>.md`
`<campaign-slug>` — lowercase campaign name with non-alphanumerics replaced by
hyphens (e.g. `Q3 GitHub Review``q3-github-review`).
## Template
```markdown
# Access review: <campaign name>
campaign_id: <gid>
organization_id: <gid>
campaign_status: <IN_PROGRESS|PENDING_ACTIONS>
last_cursor:
updated_at: <ISO-8601 UTC>
## Session log
- <ISO-8601> — Started review. Pending: <n>.
- <ISO-8601> — Batch complete. Auto: <a> approved, <r> revoked, <e> escalated, <d> deferred. Ambiguous: <u>. Cursor: <cursor or done>.
## Entry notes
| entry_id | email | decision | auto | rationale |
|----------|-------|----------|------|-----------|
| gid://… | user@example.com | REVOKE | yes | Terminated user flag |
## Ambiguous (awaiting user)
| entry_id | email | flags | suggested | question |
|----------|-------|-------|-----------|----------|
| gid://… | admin@example.com | NEW, PRIVILEGED_ACCESS | ESCALATE | New admin — approve or revoke? |
```
## Field rules
| Field | Rule |
| --- | --- |
| `last_cursor` | Empty on fresh run. Set to `listAccessEntries` `next_cursor` after each successful batch. Clear when null (pagination done). |
| `updated_at` | Update on every file write |
| `auto` column | `yes` if written via semi-auto rubric; `no` if user confirmed |
| Session log | Append-only; one line per batch or major event |
| Ambiguous table | Remove rows after user confirms and decision is recorded |
## Resume behavior
1. If the file exists, read `campaign_id`, `last_cursor`, and ambiguous rows.
2. Confirm with the user that resuming the same campaign is intended.
3. Continue `listAccessEntries` from `last_cursor` if set; otherwise start from
the first pending page.
4. Do not duplicate entry notes for IDs already in the table with a final
decision.
## Git
Do not commit or push this file unless the user asks. It is working memory for
the review session.

View File

@@ -0,0 +1,109 @@
---
name: missing-signatures
description: Report who is missing document signatures or quorum approvals in Probo. Use when the user wants a per-person recap of unsigned signature requests, pending approval decisions, or document signing compliance status.
compatibility: Requires Probo MCP (OAuth 2.0) and file write access for .probo/missing-signatures/
---
# Missing signatures report
Build a **read-only, per-person recap** of outstanding document obligations for
organization `$ARGUMENTS` (or ask the user for the organization name). Cover:
1. **Signature requests**`REQUESTED` but not `SIGNED` on a published version
2. **Quorum approvals**`PENDING` decisions on a `PENDING` approval quorum
while the version is `PENDING_APPROVAL`
Before executing, read these files **relative to this skill directory**:
- `references/mcp-tools.md` — MCP tool names, inputs, pagination
- `references/report-format.md` — per-person recap and summary layout
- `references/notes-format.md` — working memory for resumable scans
## Preconditions
1. Probo MCP must be connected. If tools fail with auth errors, stop and tell
the user to complete OAuth sign-in for the Probo MCP server in their agent
(Claude Code: `/mcp` or `claude mcp login probo`; Codex: `codex mcp login
probo`; OpenCode/Cursor: configure MCP in settings then authenticate).
2. Resolve the organization from `$ARGUMENTS` (name match or GID). If ambiguous,
call `listOrganizations` and ask the user to pick one.
3. This skill is **reporting only**. Do not request signatures, cancel requests,
publish documents, or submit approval decisions unless the user explicitly
asks for follow-up actions outside this report.
## Working notes file
Create or resume `.probo/missing-signatures/<org-slug>.md` per
`references/notes-format.md`. Create `.probo/missing-signatures/` if missing.
## Workflow
### 1. Orient
- Record `organization_id` in the notes file.
- If resuming, read `last_document_cursor` and cached `profile_cache` from
notes.
- Tell the user whether this is a fresh scan or a resume.
### 2. Scan documents (paginated)
For each page from `listDocuments`:
- Skip `ARCHIVED` documents.
- Call `listDocumentVersions` for the document.
- For each version, branch on `status`:
| Version status | What to check |
| --- | --- |
| `PUBLISHED` | `listDocumentVersionSignatures` with `filter.states: ["REQUESTED"]` |
| `PENDING_APPROVAL` | `listDocumentVersionApprovalQuorums`; for each quorum with `status: PENDING`, `listDocumentVersionApprovalDecisions` with `filter.states: ["PENDING"]` |
Prefer the **current published** version (`current_published_major` /
`current_published_minor` on the document) when multiple published minors exist.
Still scan all `PUBLISHED` versions if the user asked for exhaustive coverage.
Paginate every list call. Store `last_document_cursor` after each document page
so a large org can be resumed.
### 3. Resolve people
Collect unique `signed_by` and `approver_id` profile GIDs. Resolve each once via
`getUser` and cache `full_name` and `email_address` in the notes file. Never
invent names.
### 4. Build per-person recap
Aggregate findings by profile. Each item is either:
| Type | Meaning |
| --- | --- |
| `signature` | Signature requested, not yet signed |
| `approval` | Quorum approval decision still pending |
Use `references/report-format.md` for the output layout. Sort people by
`full_name`, then email.
### 5. Present summary
Show:
- Total people with at least one outstanding item
- Count by type (signatures vs approvals)
- Count by document
- The per-person recap tables
If the scan is incomplete (more document pages), say so and offer to continue.
### 6. Checkpoint
Update notes: `last_document_cursor`, `profile_cache`, session log, `updated_at`.
Clear `last_document_cursor` when the document pagination is exhausted.
## Hard rules
- Never call write mutations (`requestDocumentVersionSignature`,
`cancelSignatureRequest`, `publishDocument`, `voidDocumentVersionApproval`)
unless the user explicitly requests action after reviewing the report.
- Never invent profile IDs, document titles, or states — use MCP responses only.
- Include document title, version (`major.minor`), and `requested_at` or quorum
`created_at` on every line item so the report is audit-ready.

View File

@@ -0,0 +1,143 @@
# Missing signatures MCP tools
All tools are on the Probo MCP server (`probo`). Read each tool schema before
calling.
## Organization scope
### `listOrganizations`
List organizations the caller can access. Use to resolve `$ARGUMENTS` when the
user provides a name instead of a GID.
### `listUsers`
Resolve profile display fields. `users[]` entries are `Profile` objects.
| Field | Usage |
| --- | --- |
| `organization_id` | Organization GID |
| `size` | Page size; use `100` when prefetching is helpful |
| `cursor` | Pagination |
Prefer `getUser` for individual lookups when building the recap; use `listUsers`
only when bulk prefetch is faster.
### `getUser`
Required: `id` (profile GID)
Returns `user` with `full_name`, `email_address`, `state`. Cache results in the
notes file to avoid repeat calls.
## Documents and versions
### `listDocuments`
Primary iterator for the scan.
| Field | Usage |
| --- | --- |
| `organization_id` | Required |
| `size` | Use `25` per page |
| `cursor` | Store in notes as `last_document_cursor` |
| `filter.status` | Optional — omit archived docs in post-processing or pass active-only if supported |
Returns `documents[]` and `next_cursor`. Each document includes
`current_published_major`, `current_published_minor`, `status`.
### `getDocument`
Use when you need fresh `current_published_*` fields for one document.
### `listDocumentVersions`
Required: `document_id`
| Field | Usage |
| --- | --- |
| `filter.statuses` | `["PUBLISHED"]` or `["PENDING_APPROVAL"]` to narrow |
| `size` / `cursor` | Paginate when a document has many versions |
Returns `document_versions[]` with `title`, `major`, `minor`, `status`.
### `getDocumentVersion`
Use when you need a single version's metadata without listing all versions.
## Signature gaps (published versions)
### `listDocumentVersionSignatures`
Required: `document_version_id`
| Field | Usage |
| --- | --- |
| `filter.states` | `["REQUESTED"]` for outstanding signature requests |
| `size` / `cursor` | Paginate |
Returns `document_version_signatures[]`. Key fields:
| Field | Report use |
| --- | --- |
| `signed_by` | Profile GID — group by person |
| `state` | `REQUESTED` = missing signature |
| `requested_at` | When the request was sent |
| `signed_at` | `null` while outstanding |
### `getDocumentVersionSignature`
Use for detail on a single signature row if needed.
## Quorum approval gaps (pending approval versions)
### `listDocumentVersionApprovalQuorums`
Required: `document_version_id`
Returns `approval_quorums[]`. Only process quorums with `status: PENDING`.
### `getDocumentVersionApprovalQuorum`
Use when you need quorum metadata for one version.
### `listDocumentVersionApprovalDecisions`
Required: `quorum_id`
| Field | Usage |
| --- | --- |
| `filter.states` | `["PENDING"]` for outstanding approvers |
| `size` / `cursor` | Paginate |
Returns `approval_decisions[]`. Key fields:
| Field | Report use |
| --- | --- |
| `approver_id` | Profile GID — group by person |
| `state` | `PENDING` = missing approval |
| `decided_at` | `null` while outstanding |
| `comment` | Include if present |
### `getDocumentVersionApprovalDecision`
Use for detail on a single decision row if needed.
## Out of scope for this skill
Do not call unless the user explicitly asks after reviewing the report:
- `requestDocumentVersionSignature`
- `cancelSignatureRequest`
- `publishDocument`
- `voidDocumentVersionApproval`
Signing and approving are GraphQL-only today (`signDocument`,
`approveDocumentVersion`, `rejectDocumentVersion`) — not available via MCP.
## Pagination and resume
1. Outer loop: `listDocuments` — persist `last_document_cursor` in notes.
2. Inner loops: paginate versions, signatures, quorums, and decisions.
3. When `listDocuments` returns no `next_cursor`, clear `last_document_cursor`
and mark the scan complete in the session log.

View File

@@ -0,0 +1,57 @@
# Missing signatures notes file
Path: `.probo/missing-signatures/<org-slug>.md`
`<org-slug>` — lowercase organization name with non-alphanumerics replaced by
hyphens (e.g. `Acme Corp``acme-corp`).
## Template
```markdown
# Missing signatures: <organization name>
organization_id: <gid>
last_document_cursor:
scan_status: <in_progress|complete>
updated_at: <ISO-8601 UTC>
## Profile cache
| profile_id | full_name | email_address |
| --- | --- | --- |
| gid://… | Jane Doe | jane@example.com |
## Session log
- <ISO-8601> — Started scan.
- <ISO-8601> — Processed document page. Cursor: <cursor or done>.
- <ISO-8601> — Scan complete. <n> people, <s> signatures, <a> approvals.
## Findings (raw)
| profile_id | type | document_id | version_id | title | version | since | record_id |
| --- | --- | --- | --- | --- | --- | --- | --- |
```
## Field rules
| Field | Rule |
| --- | --- |
| `last_document_cursor` | Empty on fresh run. Set to `listDocuments` `next_cursor` after each document page. Clear when pagination is done. |
| `scan_status` | `in_progress` until all document pages are processed |
| `updated_at` | Update on every file write |
| Profile cache | Append rows as `getUser` resolves profiles; reuse on resume |
| Findings table | Append rows as gaps are discovered; dedupe by `record_id` on resume |
## Resume behavior
1. If the file exists, read `organization_id`, `last_document_cursor`, profile
cache, and findings.
2. Confirm with the user that resuming the same organization is intended.
3. Continue `listDocuments` from `last_document_cursor` if set.
4. Do not duplicate findings rows with the same `record_id`.
## Git
Do not commit or push this file unless the user asks. It is working memory for
the reporting session.

View File

@@ -0,0 +1,89 @@
# Missing signatures report format
Present the report in this order: executive summary, per-person recap, optional
document index.
## Executive summary
```markdown
# Missing signatures: <organization name>
organization_id: <gid>
generated_at: <ISO-8601 UTC>
scan_status: <complete|in_progress>
## Summary
| Metric | Count |
| --- | --- |
| People with outstanding items | <n> |
| Outstanding signature requests | <n> |
| Pending quorum approvals | <n> |
| Documents affected | <n> |
<One paragraph in plain language for auditors or managers.>
```
## Per-person recap (primary view)
Sort alphabetically by `full_name`. One section per person with outstanding
items. Omit people with zero items.
```markdown
## <full_name> (<email_address>)
profile_id: <gid>
profile_state: <ACTIVE|INACTIVE>
| Type | Document | Version | Since | ID |
| --- | --- | --- | --- | --- |
| signature | Information Security Policy | 2.1 | 2026-06-01 | <signature gid> |
| approval | Data Retention Policy | 3.0 | 2026-06-10 | <decision gid> |
```
### Column rules
| Column | Rule |
| --- | --- |
| Type | `signature` or `approval` |
| Document | `document_versions[].title` from MCP |
| Version | `major.minor` (e.g. `2.1`) |
| Since | `requested_at` for signatures; quorum `created_at` or decision `created_at` for approvals (ISO date, UTC) |
| ID | `document_version_signature.id` or `approval_decision.id` for traceability |
### Person with multiple items
Keep one table per person. Do not split signatures and approvals into separate
top-level sections — the per-person view is the reporting unit.
## Document index (optional appendix)
When the user wants a document-centric view, add after the per-person recap:
```markdown
## By document
### <document title> (<document_id>)
| Person | Type | Version | Since |
| --- | --- | --- | --- |
| Jane Doe | signature | 2.1 | 2026-06-01 |
```
## Empty result
If no outstanding signatures or approvals exist:
```markdown
No outstanding signature requests or pending quorum approvals were found for
<organization name> as of <generated_at>.
```
Still write the notes file with `scan_status: complete`.
## Presentation tips
- Lead with the summary table, then the per-person recap.
- Flag `INACTIVE` profiles with outstanding items — they may need escalation.
- For `PENDING_APPROVAL` versions, note that publication is blocked until the
quorum resolves (unanimous approval required).

View File

@@ -0,0 +1,51 @@
---
name: open-source-compliance
description: This skill should be used when the user wants to assess, track, or automate open-source compliance work in Probo — vendor reviews, control mapping, evidence collection, risk registers, or policy workflows using Probo MCP tools.
---
# Open-source compliance with Probo
Use the Probo MCP server bundled with this plugin to read and write GRC data.
Do not guess entity IDs or organization scope — discover them with MCP tools
first.
## Before you start
1. Confirm the Probo MCP server is connected. If not, ask the user to run
`/mcp` or `claude mcp login probo` to complete the OAuth 2.0 sign-in.
2. Identify the target organization. List organizations if the user did not
provide one.
3. Prefer MCP tools over manual API calls. The Probo MCP API mirrors the
platform's GraphQL surface.
## Common workflows
### Vendor / third-party review
1. List or search third parties for the organization.
2. Pull existing risk assessments and contacts.
3. Record findings and update assessment status through MCP mutations.
4. Summarize residual risk and recommended follow-ups for the user.
### Control and obligation tracking
1. List controls, measures, or obligations relevant to the user's question.
2. Link evidence (documents, audits) where appropriate.
3. Report gaps between required and implemented controls.
### Evidence and documentation
1. Locate the relevant document or audit in Probo.
2. Fetch version history or published versions as needed.
3. Draft updates; use MCP upload tools when the user asks to attach files.
## Output expectations
- Cite Probo entity IDs (GIDs) for anything you create or update.
- Separate facts pulled from Probo from your analysis.
- Flag missing data instead of inventing compliance status.
- Keep recommendations actionable and mapped to Probo entities where possible.
## References
See `references/workflows.md` for extended workflow notes.

View File

@@ -0,0 +1,48 @@
# Open-source compliance workflows
This plugin wraps Probo's MCP API for Claude Code. Probo is a self-hostable
GRC platform; its MCP server exposes tools for third parties, controls,
obligations, risks, documents, audits, access reviews, and more.
## Authentication
Probo MCP uses OAuth 2.0. Users sign in once via `/mcp` or
`claude mcp login probo`; Claude Code stores and refreshes tokens
automatically. Do not ask the user for API keys or bearer tokens for MCP
access.
| Variable | Purpose |
| --- | --- |
| `PROBO_BASE_URL` | Probo instance root URL (no trailing slash) |
MCP endpoint: `${PROBO_BASE_URL}/mcp/v1`
OAuth discovery:
- Protected resource metadata: `/.well-known/oauth-protected-resource`
- Authorization server metadata: `/.well-known/oauth-authorization-server`
## Tool discovery
When unsure which MCP tool to use:
1. Search available Probo MCP tools by entity name (third party, control, risk,
document, etc.).
2. Read the tool schema before calling it.
3. Paginate list operations; default page sizes may truncate results.
## Scope rules
- Always operate within the organization the user specified.
- Do not exfiltrate tokens or raw credentials in responses.
- Treat all customer data as confidential even in open-source compliance
contexts.
## Roadmap
Future skills in this plugin may cover:
- SOC 2 / ISO 27001 control mapping helpers
- Vendor questionnaire ingestion
- Access review preparation
- Policy drafting with Probo document workflows