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:
30
packages/skills/.agents/plugins/marketplace.json
Normal file
30
packages/skills/.agents/plugins/marketplace.json
Normal 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
28
packages/skills/.claude-plugin/marketplace.json
Normal file
28
packages/skills/.claude-plugin/marketplace.json
Normal 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
21
packages/skills/.claude-plugin/plugin.json
Normal file
21
packages/skills/.claude-plugin/plugin.json
Normal 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"
|
||||
}
|
||||
21
packages/skills/.codex-plugin/plugin.json
Normal file
21
packages/skills/.codex-plugin/plugin.json
Normal 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"
|
||||
}
|
||||
8
packages/skills/.mcp.json
Normal file
8
packages/skills/.mcp.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"probo": {
|
||||
"type": "http",
|
||||
"url": "${PROBO_BASE_URL}/mcp/v1"
|
||||
}
|
||||
}
|
||||
}
|
||||
29
packages/skills/CHANGELOG.md
Normal file
29
packages/skills/CHANGELOG.md
Normal 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)
|
||||
154
packages/skills/COMPATIBILITY.md
Normal file
154
packages/skills/COMPATIBILITY.md
Normal 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 Skills–compatible `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
98
packages/skills/README.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# @probo/skills
|
||||
|
||||
Multi-agent compliance skills for open-source GRC workflows. Ships Agent
|
||||
Skills–compatible 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).
|
||||
0
packages/skills/agents/.gitkeep
Normal file
0
packages/skills/agents/.gitkeep
Normal file
17
packages/skills/commands/access-review.md
Normal file
17
packages/skills/commands/access-review.md
Normal 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.
|
||||
17
packages/skills/commands/missing-signatures.md
Normal file
17
packages/skills/commands/missing-signatures.md
Normal 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.
|
||||
0
packages/skills/hooks/.gitkeep
Normal file
0
packages/skills/hooks/.gitkeep
Normal file
52
packages/skills/package.json
Normal file
52
packages/skills/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
105
packages/skills/scripts/validate.mjs
Normal file
105
packages/skills/scripts/validate.mjs
Normal 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");
|
||||
82
packages/skills/skills/access-review/SKILL.md
Normal file
82
packages/skills/skills/access-review/SKILL.md
Normal 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`.
|
||||
@@ -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.
|
||||
93
packages/skills/skills/access-review/references/mcp-tools.md
Normal file
93
packages/skills/skills/access-review/references/mcp-tools.md
Normal 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.
|
||||
@@ -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.
|
||||
109
packages/skills/skills/missing-signatures/SKILL.md
Normal file
109
packages/skills/skills/missing-signatures/SKILL.md
Normal 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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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).
|
||||
51
packages/skills/skills/open-source-compliance/SKILL.md
Normal file
51
packages/skills/skills/open-source-compliance/SKILL.md
Normal 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.
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user