Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "stackguardian",
"owner": {
"name": "StackGuardian",
"url": "https://www.stackguardian.io"
},
"description": "Agent skills for Terraform and OpenTofu, and for StackGuardian.",
"plugins": [
{
"name": "terraform",
"source": ".",
"description": "Terraform and OpenTofu skills that work in any repository and need no StackGuardian account.",
"skills": ["./standalone"]
},
{
"name": "stackguardian",
"source": ".",
"description": "Create and manage StackGuardian workflows, stacks, policies and secrets. Needs the StackGuardian MCP server: run npx @stackguardian/mcp-wizard.",
"skills": ["./skills"]
}
]
}
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ jobs:
- name: Install dependencies
run: bun install --frozen-lockfile

- name: Check the Tirith skill copies
run: node scripts/sync-tirith-skills.mjs --check

- name: Type check
run: bun run typecheck

Expand Down
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Copies synced from StackGuardian/tirith (scripts/sync-tirith-skills.mjs); formatting them would break the sync check.
standalone/tirith-*/
37 changes: 33 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
# StackGuardian MCP - Deploy Terraform, OpenTofu and Ansible with your AI coding agent
# Deploy Terraform with AI, without losing control

[![npm](https://img.shields.io/npm/v/@stackguardian/mcp-wizard)](https://www.npmjs.com/package/@stackguardian/mcp-wizard)
[![CI](https://github.com/StackGuardian/stackguardian-mcp/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/StackGuardian/stackguardian-mcp/actions/workflows/ci.yml)
[![License](https://img.shields.io/github/license/StackGuardian/stackguardian-mcp)](LICENSE)
[![MCP](https://img.shields.io/badge/MCP-compatible-blue)](https://modelcontextprotocol.io)
[![Agent Skills](https://img.shields.io/badge/Agent%20Skills-included-blue)](skills/README.md)

One-command MCP setup and ready-to-use agent skills for Claude Code, Cursor, Codex and [more](#supported-agents).
Review Terraform changes, gate them with policy and deploy from Claude Code, Cursor or Codex. Start locally; add managed execution, approvals and run history when your team needs them.

Connect your coding agent to [StackGuardian](https://www.stackguardian.io), the platform that runs and governs your infrastructure deployments. Then ask in plain language to turn your existing infrastructure code into deployment workflows, review changes, require approvals, add policies and find out why a run failed.
| | Works with any repo | With StackGuardian |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Skills | [`tirith-policies`](standalone/tirith-policies/SKILL.md) | [Six `sg-*` skills](#mcp-and-skills) for workflows, stacks, policies and secrets |
| What your agent can do | Write and run [Tirith](https://github.com/StackGuardian/tirith) policy checks on your Terraform and OpenTofu plans, and add them to CI | Create and run deployment workflows, require approvals, add policies and find out why a run failed, in your StackGuardian organization |
| You need | Terraform or OpenTofu, and Python 3.8 or later for Tirith. No account. | A StackGuardian account and the StackGuardian MCP server |
| Install | [`npx skills add …`](#works-with-any-repo) | [`npx @stackguardian/mcp-wizard`](#with-stackguardian) |

## Works with any repo

Install the standalone skills with the [skills CLI](https://github.com/vercel-labs/skills). It asks which agents to install to; add `-a claude-code`, `-a cursor` or `-a codex` to choose, and `-g` to install for your user instead of the current project.

```bash
npx skills add https://github.com/StackGuardian/stackguardian-mcp/tree/main/standalone
```

In Claude Code you can install them as a plugin instead:

```bash
claude plugin install terraform --marketplace StackGuardian/stackguardian-mcp
```

**Then try asking your agent:**

> Write a Tirith policy that fails the plan if any S3 bucket is public, and test it against our plan.

> Add a Tirith check to our GitHub Actions workflow before `terraform apply`.

## With StackGuardian

Connect your coding agent to [StackGuardian](https://www.stackguardian.io), the platform that runs and governs your infrastructure deployments. One command adds the StackGuardian MCP server to your agents and installs the six `sg-*` skills:

```bash
npx @stackguardian/mcp-wizard
Expand All @@ -26,7 +55,7 @@ No Node.js? Use the [one-line installer](#install) for macOS, Linux or Windows.

[Get started](#get-started) · [Supported agents](#supported-agents) · [Skills](#mcp-and-skills) · [Skills guide](skills/README.md)

## What you can do
### What you can do with StackGuardian

| Goal | Ask your agent, for example | What happens |
| ------------------------------ | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
Expand Down
189 changes: 189 additions & 0 deletions catalog/skills.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
{
"version": 1,
"skills": [
{
"slug": "tirith-policies",
"title": "Tirith Policies",
"tier": "standalone",
"requiresStackGuardian": false,
"category": "Policy",
"summary": "Write, validate and run Tirith policy-as-code checks on Terraform and OpenTofu plans, and add them to a CI pipeline.",
"description": "Tirith checks the plan your pipeline already produces against JSON policies and exits non-zero when a change breaks one. This skill helps your agent write those policies, run them against a document that should fail, read Tirith's results and exit codes, and add the check to GitHub Actions, GitLab CI, Bitbucket Pipelines, Jenkins, Azure DevOps or CircleCI.",
"examplePrompts": [
"Write a Tirith policy that fails the plan if any S3 bucket is public.",
"Add a Tirith check to our GitHub Actions workflow before terraform apply.",
"Why did the Tirith step fail in CI?"
],
"supportedAgents": ["Claude Code"],
"prerequisites": [
"Terraform or OpenTofu",
"Python 3.8 or later for Tirith"
],
"install": {
"skillsCli": "npx skills add https://github.com/StackGuardian/stackguardian-mcp/tree/main/standalone --skill tirith-policies",
"claudePlugin": "claude plugin install terraform --marketplace StackGuardian/stackguardian-mcp"
},
"githubPath": "standalone/tirith-policies",
"demoUrl": null,
"relatedSlugs": ["sg-create-policy"]
},
{
"slug": "sg-create-workflow",
"title": "Create a StackGuardian Workflow",
"tier": "platform",
"requiresStackGuardian": true,
"category": "Platform",
"summary": "Create a StackGuardian workflow for Terraform, OpenTofu or a custom step pipeline, from your git repository or a library template.",
"description": "Your agent asks whether the code comes from your own git repository or a StackGuardian library template, then walks you through the workflow group, cloud connector, variables and template inputs. You see every input with the value that will be used before anything is created. Creating a workflow does not deploy anything; a deployment happens when a run starts.",
"examplePrompts": [
"Create a workflow for the Terraform in github.com/acme/infra, folder envs/staging, branch main.",
"Create an OpenTofu workflow from our repo that needs approval before every apply.",
"Set up a workflow that runs our Ansible playbook as a custom step."
],
"supportedAgents": ["Claude Code"],
"prerequisites": [
"A StackGuardian account",
"The StackGuardian MCP server: npx @stackguardian/mcp-wizard"
],
"install": {
"skillsCli": "npx skills add StackGuardian/stackguardian-mcp --skill sg-create-workflow",
"claudePlugin": "claude plugin install stackguardian --marketplace StackGuardian/stackguardian-mcp"
},
"githubPath": "skills/sg-create-workflow",
"demoUrl": null,
"relatedSlugs": [
"sg-update-workflow",
"sg-upgrade-workflow",
"sg-create-stack"
]
},
{
"slug": "sg-update-workflow",
"title": "Update a StackGuardian Workflow",
"tier": "platform",
"requiresStackGuardian": true,
"category": "Platform",
"summary": "Change an existing StackGuardian workflow's connector, variables, schedules, approvals, runner or sizing. Only what you change is touched.",
"description": "Your agent finds the workflow, confirms it is the one you mean, and changes only the settings you ask for. For settings saved as a whole list, such as tags or schedules, it reads the current list first so adding one entry keeps the others. You confirm a summary before anything changes.",
"examplePrompts": [
"Add a nightly 2 AM schedule to prod-vpc.",
"Require approval from alice@example.com or bob@example.com before prod-vpc applies.",
"prod-vpc runs keep running out of memory. Give them 4 GB."
],
"supportedAgents": ["Claude Code"],
"prerequisites": [
"A StackGuardian account",
"The StackGuardian MCP server: npx @stackguardian/mcp-wizard"
],
"install": {
"skillsCli": "npx skills add StackGuardian/stackguardian-mcp --skill sg-update-workflow",
"claudePlugin": "claude plugin install stackguardian --marketplace StackGuardian/stackguardian-mcp"
},
"githubPath": "skills/sg-update-workflow",
"demoUrl": null,
"relatedSlugs": ["sg-create-workflow", "sg-upgrade-workflow"]
},
{
"slug": "sg-upgrade-workflow",
"title": "Upgrade a StackGuardian Workflow",
"tier": "platform",
"requiresStackGuardian": true,
"category": "Platform",
"summary": "Move a StackGuardian workflow to another template revision, with a dry run that shows every change first.",
"description": "Your agent finds the workflow and the revision to move to, and asks whether to keep your settings or reset to the template. A dry run shows how many settings would be added, changed or removed before anything is applied. You review template inputs, environment variables, the cloud connector and custom step settings, then confirm.",
"examplePrompts": [
"Upgrade prod-vpc to the latest revision of its template.",
"What would change if I moved prod-vpc to revision 5 of its template?",
"Roll prod-vpc back to the previous template revision."
],
"supportedAgents": ["Claude Code"],
"prerequisites": [
"A StackGuardian account",
"The StackGuardian MCP server: npx @stackguardian/mcp-wizard"
],
"install": {
"skillsCli": "npx skills add StackGuardian/stackguardian-mcp --skill sg-upgrade-workflow",
"claudePlugin": "claude plugin install stackguardian --marketplace StackGuardian/stackguardian-mcp"
},
"githubPath": "skills/sg-upgrade-workflow",
"demoUrl": null,
"relatedSlugs": ["sg-update-workflow", "sg-create-workflow"]
},
{
"slug": "sg-create-stack",
"title": "Create a StackGuardian Stack",
"tier": "platform",
"requiresStackGuardian": true,
"category": "Platform",
"summary": "Create several related StackGuardian workflows together from a stack template, reviewing each workflow's inputs.",
"description": "Your agent helps you pick a stack template, then walks through each workflow's inputs one workflow at a time. Inputs that come from another workflow's output are filled in for you, and the agent says where each one comes from. Creating a stack does not deploy anything until you start it.",
"examplePrompts": [
"Find a stack template that sets up a VPC, a security group and an EC2 instance.",
"Create a stack from that template in the staging group with our AWS staging connector."
],
"supportedAgents": ["Claude Code"],
"prerequisites": [
"A StackGuardian account",
"The StackGuardian MCP server: npx @stackguardian/mcp-wizard"
],
"install": {
"skillsCli": "npx skills add StackGuardian/stackguardian-mcp --skill sg-create-stack",
"claudePlugin": "claude plugin install stackguardian --marketplace StackGuardian/stackguardian-mcp"
},
"githubPath": "skills/sg-create-stack",
"demoUrl": null,
"relatedSlugs": ["sg-create-workflow", "sg-create-policy"]
},
{
"slug": "sg-create-policy",
"title": "Create a StackGuardian Policy",
"tier": "platform",
"requiresStackGuardian": true,
"category": "Platform",
"summary": "Add a StackGuardian guardrail that blocks, warns on or requires approval for infrastructure changes.",
"description": "Your agent offers a library policy template when one fits, a Tirith rule it writes and explains back to you, or your own git repository of Rego or Tirith policies. You choose what happens when a rule fails, where the policy applies and who can approve. An organization-wide policy is confirmed explicitly.",
"examplePrompts": [
"Block any deployment in the prod group that makes an S3 bucket public.",
"Warn when the estimated monthly cost of an EC2 instance goes over $100."
],
"supportedAgents": ["Claude Code"],
"prerequisites": [
"A StackGuardian account",
"The StackGuardian MCP server: npx @stackguardian/mcp-wizard"
],
"install": {
"skillsCli": "npx skills add StackGuardian/stackguardian-mcp --skill sg-create-policy",
"claudePlugin": "claude plugin install stackguardian --marketplace StackGuardian/stackguardian-mcp"
},
"githubPath": "skills/sg-create-policy",
"demoUrl": null,
"relatedSlugs": ["tirith-policies", "sg-create-workflow"]
},
{
"slug": "sg-manage-secrets",
"title": "Manage StackGuardian Secrets",
"tier": "platform",
"requiresStackGuardian": true,
"category": "Platform",
"summary": "Store, rotate or delete StackGuardian vault secrets and use them in workflows.",
"description": "Your agent stores a token, password or key in the StackGuardian vault and shows you how workflows refer to it by name. Before deleting a secret, it lists the workflows that mention it and deletes only after you agree. A secret's value can't be read back, only replaced.",
"examplePrompts": [
"Store a GitHub token as a secret called GITHUB_TOKEN.",
"Rotate the DB_PASSWORD secret.",
"Delete the OLD_API_KEY secret. Which workflows still use it?"
],
"supportedAgents": ["Claude Code"],
"prerequisites": [
"A StackGuardian account",
"The StackGuardian MCP server: npx @stackguardian/mcp-wizard"
],
"install": {
"skillsCli": "npx skills add StackGuardian/stackguardian-mcp --skill sg-manage-secrets",
"claudePlugin": "claude plugin install stackguardian --marketplace StackGuardian/stackguardian-mcp"
},
"githubPath": "skills/sg-manage-secrets",
"demoUrl": null,
"relatedSlugs": ["sg-create-workflow", "sg-update-workflow"]
}
]
}
110 changes: 110 additions & 0 deletions scripts/sync-tirith-skills.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env node
// Copies the Tirith skills from StackGuardian/tirith, pinned to the tag in
// standalone/TIRITH_VERSION, into standalone/. The copies are never edited by
// hand: change them upstream in Tirith, then bump the tag and run this again.
//
// Usage:
// node scripts/sync-tirith-skills.mjs overwrite standalone/<skill>
// node scripts/sync-tirith-skills.mjs --check fail if the committed copy differs
import { spawnSync } from "node:child_process";
import {
cpSync,
existsSync,
mkdtempSync,
readFileSync,
readdirSync,
rmSync,
statSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join, relative } from "node:path";
import { fileURLToPath } from "node:url";

const TIRITH_REPO = "https://github.com/StackGuardian/tirith.git";
// tirith-standards and tirith-migrate join this list once a Tirith release
// contains them; 1.2.1 ships only tirith-policies.
const TIRITH_SKILLS = ["tirith-policies"];

const repoRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
const standaloneDir = join(repoRoot, "standalone");
const tag = readFileSync(join(standaloneDir, "TIRITH_VERSION"), "utf-8").trim();
const check = process.argv.includes("--check");

function listFiles(dir) {
return readdirSync(dir, { recursive: true })
.map(String)
.filter((path) => statSync(join(dir, path)).isFile())
.sort();
}

/** Returns a description of every difference between two directory trees. */
function diffTrees(expected, actual) {
if (!existsSync(actual)) return [`${relative(repoRoot, actual)} is missing`];
const want = listFiles(expected);
const have = listFiles(actual);
const problems = [];
for (const path of want) {
if (!have.includes(path)) problems.push(`missing ${path}`);
else if (
!readFileSync(join(expected, path)).equals(
readFileSync(join(actual, path)),
)
)
problems.push(`changed ${path}`);
}
for (const path of have) {
if (!want.includes(path)) problems.push(`unexpected ${path}`);
}
return problems;
}

const work = mkdtempSync(join(tmpdir(), "tirith-skills-"));
try {
const clone = spawnSync(
"git",
[
"-c",
"advice.detachedHead=false",
"clone",
"--quiet",
"--depth",
"1",
"--branch",
tag,
TIRITH_REPO,
work,
],
{ stdio: "inherit" },
);
if (clone.status !== 0) {
throw new Error(`git clone of ${TIRITH_REPO} at ${tag} failed`);
}

const problems = [];
for (const skill of TIRITH_SKILLS) {
const source = join(work, ".claude", "skills", skill);
if (!existsSync(join(source, "SKILL.md"))) {
throw new Error(`Tirith ${tag} has no .claude/skills/${skill}/SKILL.md`);
}
const target = join(standaloneDir, skill);
if (check) {
problems.push(...diffTrees(source, target).map((p) => `${skill}: ${p}`));
} else {
rmSync(target, { recursive: true, force: true });
cpSync(source, target, { recursive: true });
console.log(`synced ${skill} from Tirith ${tag}`);
}
}

if (problems.length > 0) {
console.error(
`standalone/ does not match Tirith ${tag}. Do not edit these files by hand; run node scripts/sync-tirith-skills.mjs.`,
);
for (const problem of problems) console.error(` ${problem}`);
process.exitCode = 1;
} else if (check) {
console.log(`standalone/ matches Tirith ${tag}`);
}
} finally {
rmSync(work, { recursive: true, force: true });
}
Loading
Loading