{
  "markdown": "# linebreak-gate — the LineBreak security gate at the git/CI boundary\n\n<!-- mcp-name: com.linebreakapp/linebreak-gate -->\n\n## See it run\n\nA real pull request, blocked for real: the gate is a **required check**, so the merge button goes gray until the CVE is fixed or a named human records an override.\n\n![Real pull request blocked by the LineBreak Security Gate: required check failing, merge disabled](https://raw.githubusercontent.com/Baktun-Studio/linebreak-gate/main/assets/pr-blocked.png)\n\n**[See it live — a public PR you can open right now →](https://github.com/Baktun-Studio/gate-demo/pull/1)**\n\nA real recording, no mock: the scan blocks a critical CVE fail-closed, the pin gets fixed, the gate opens.\n\n![linebreak-gate scan blocking a critical CVE, then passing after the fix](https://www.linebreakapp.com/demo/gate.gif)\n\nThe spec loop: a named human approves the criteria, `check` blocks until the manual criterion carries a sign-off, then everything passes.\n\n![spec approve, check blocked until sign-off, then all criteria pass](https://www.linebreakapp.com/demo/spec.gif)\n\nBlocks merges that carry known vulnerabilities. One tool, two detectors —\n**dependency scanning is free; the AI review is the Pro upgrade**:\n\n- **Dependency CVE scan — free, no key** — [osv-scanner](https://google.github.io/osv-scanner/)\n  across every ecosystem (npm, PyPI, Go, Cargo, Maven, …), with an `npm audit`\n  fallback for npm projects (npm-only coverage and no installed-version data —\n  the GitHub Action fails closed if osv-scanner can't be installed instead of\n  degrading to it).\n- **AI SAST — Pro** — an LLM security review of first-party source (injection,\n  broken auth, secret exposure, SSRF, unsafe deserialization, crypto misuse)\n  with adversarial verification, enabled by `LINEBREAK_LICENSE_KEY` (hosted,\n  uses credits) or `ANTHROPIC_API_KEY` (your own key, takes precedence). Without\n  a key the dependency scan still runs and this pass is skipped with a notice.\n\nThe gate **blocks and can propose; it never auto-clears on an agent's\nsay-so**. A human approves the fix or records an override — with a reason and\nan approver — in a git-committed audit file.\n\nThis is the same scanner core that powers the rest of LineBreak's in-product\nsecurity gate (the desktop backend imports this package), but it is fully\nstandalone: a team that has never touched anything else from LineBreak can add the gate to\ntheir repo and get real enforcement.\n\n> **Contributing & license.** This repo is the published source of\n> [`linebreak-gate`](https://pypi.org/project/linebreak-gate/) (Apache-2.0):\n> every release lands here and on PyPI from our CI, and every change passed\n> our own gate first — CVE scan and human-approved criteria, the same\n> discipline we sell. Bug reports and feature requests: open an issue or\n> discussion here; we read everything. Direct PRs to this repo can't be\n> merged (releases flow through our review pipeline), so start with an issue\n> and we'll take it from there.\n\n## Quickstart — GitHub Actions\n\n```yaml\n# .github/workflows/security-gate.yml\nname: Security gate\non:\n  pull_request:\n\npermissions:\n  contents: read\n  pull-requests: write # for the summary comment\n\njobs:\n  gate:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v5\n      - uses: Baktun-Studio/linebreak-gate@v1\n        with:\n          # fail-on: high # blocking floor; default: critical\n          # Optional today; required once license enforcement is enabled.\n          license-key: ${{ secrets.LINEBREAK_LICENSE_KEY }}\n          # Enables the AI code review; leave unset for dependency scan only.\n          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}\n```\n\nThe action runs `linebreak-gate scan`, always runs `report`, posts **one** PR\ncomment (updated in place on every push, never spammed), uploads the JSON\nreport + audit artifacts as a workflow artifact, and fails the check per the\nscan's exit code.\n\n### Make it a real boundary: require the check\n\nA CI job that can be ignored is a dashboard, not a gate. In your repo:\n\n**Settings → Branches → Branch protection rules → your default branch →\n\"Require status checks to pass before merging\"** → add the `gate` job (the\nname of the job that runs this action). From then on a PR carrying a critical\nCVE cannot be merged through the GitHub UI.\n\n## Quickstart — any other CI (GitLab example)\n\nThe CLI is a plain Python package with strict exit codes — `0` pass, `1`\nblocking findings, `2` tool/config error (**fail closed**: a scanner crash\nfails the pipeline, it is never a clean pass). Any CI that respects exit codes\ngets the same enforcement:\n\n```yaml\n# .gitlab-ci.yml\nsecurity-gate:\n  image: python:3.11\n  script:\n    - pip install linebreak-gate\n    - curl -fsSL -o /usr/local/bin/osv-scanner\n      \"$(curl -fsSL https://api.github.com/repos/google/osv-scanner/releases/latest\n      | python -c \"import json,sys;print(next(a['browser_download_url'] for a in json.load(sys.stdin)['assets'] if a['name'].endswith('linux_amd64')))\")\"\n    - chmod +x /usr/local/bin/osv-scanner\n    - linebreak-gate scan\n    - linebreak-gate report\n```\n\nMark the job as required (no `allow_failure`) and protect the branch.\n\n## The spec loop — author, approve, serve over MCP, enforce\n\nThe gate also enforces **approved acceptance criteria**, and the whole loop is\ntool-agnostic — no LineBreak account, no desktop app, no server:\n\n```bash\nlinebreak-gate spec new        # scaffold a draft — fill it with any tool (your\n                               # editor, Claude Code, ChatGPT), or distill it\n                               # from the PRD you already have in Notion/Jira\nlinebreak-gate spec approve .linebreak/spec-draft.yml \\\n  --approver \"Ana Lopez <ana@example.com>\"   # a human on the record; commits\nlinebreak-gate mcp install --editor claude-code   # or: cursor · codex\n```\n\n`linebreak-gate mcp` serves the **approved** bundle (`.linebreak/spec/`) over\nMCP (stdio) to Claude Code, Cursor, Codex, or any MCP client. Six tools:\n`list_stories`, `get_story` (criteria as agent context BEFORE code is\nwritten), `next_story`, `set_story_status`, `check_story` (the same\nevaluation engine CI runs, scoped to one story), and `spec_status` (approval +\noffline signature state). **Git is the transport** — no network, no account,\nworks on a bare clone — and **nothing in the bridge can write, edit, or\ninvalidate an approved criterion**: criteria change only by editing the draft\nand re-approving, with a human on the record.\n\nThen `linebreak-gate check` enforces the same criteria in CI: machine checks\nrun for real, `manual` criteria block until a recorded sign-off. Guided first\nrun with the why of every step:\n[linebreakapp.com/en/start](https://www.linebreakapp.com/en/start).\n\n## CLI\n\n```text\nlinebreak-gate init     [--path .] [--fail-on critical|high|medium|low] [--force] [--non-interactive]\nlinebreak-gate scan     [--path .] [--fail-on critical|high|medium|low] [--format summary|json]\nlinebreak-gate report   [--path .] [--format summary|json]\nlinebreak-gate override --finding <id> --reason \"…\" --approver <name/email> [--path .]\nlinebreak-gate override --criterion <id> --reason \"…\" --approver <name/email> [--path .]\nlinebreak-gate check    [--path .] [--format summary|json] [--story <id> ...|--started-only] [--manual block|warn]\nlinebreak-gate signoff  --criterion <id> --approver <name/email> --note \"…\" [--path .]\nlinebreak-gate spec new     [--path .] [--out <file>] [--force]\nlinebreak-gate spec approve <draft> --approver <name/email> [--role architect] [--path .]\nlinebreak-gate spec list|next [--path .]\nlinebreak-gate spec show|check <story-id> [--path .]\nlinebreak-gate mcp      [--path .]            # serve the approved spec over stdio\nlinebreak-gate mcp install [--editor claude-code|cursor|codex] [--print]\nlinebreak-gate badge    [--format markdown|html|url]\n```\n\n- `init` sets a repo up in one command: writes the workflow file (never\n  clobbers an existing one without `--force`), optionally writes\n  `.linebreak/gate.yml`, offers to store the secrets via the GitHub CLI and to\n  require the `gate` check — and prints the exact settings links for anything\n  it can't do for you.\n\n- `scan` runs both detectors, writes git-native audit artifacts under\n  `.linebreak/audit/`, and exits 0/1/2.\n- `report` renders the recorded scan: counts by severity and every finding\n  with CVE id, CVSS, advisory link, and override status. `--format json` for\n  machines.\n- `override` records a human-approved acknowledgment of **one exact finding**\n  — the package + installed version + CVE tuple. A different CVE, a bumped\n  version, or a new finding still blocks. `--reason` and `--approver` are\n  required; the record lands in the artifact's approval trail. Commit the\n  updated `.linebreak/audit/*.json` so CI sees it.\n- `check` evaluates the approved acceptance criteria (`.linebreak/spec/`,\n  landed by `spec approve`) against\n  the working tree: `build`/`tests`/`command` run for real, `manual` requires\n  a recorded sign-off. Exit 0 all satisfied (or no bundle — a clean no-op), 1\n  blocking (fail or needs-signoff), 2 tool/config/bundle error (fail closed).\n  Writes `.linebreak/audit/criteria.json`. Scope flags (see\n  [Check scope](#check-scope-per-story-on-prs-full-at-release)): `--story <id>`\n  (repeatable) evaluates only those stories, `--started-only` evaluates only\n  stories with a started local state, `--manual warn` reports missing\n  sign-offs without blocking. The summary and the JSON state the scope.\n- `signoff` records an attributed human sign-off for one `manual` criterion\n  under `.linebreak/spec/signoffs/` (additive; `--approver` and `--note`\n  required). It binds to the criterion as approved — editing the criterion\n  and re-approving the spec makes prior sign-offs stale. Commit the record.\n- `override --criterion` records a human-approved override for one failed\n  machine criterion in `.linebreak/audit/criteria.json` — same philosophy as\n  CVE overrides: possible, always attributed, stale once the criterion is\n  edited. Other blocking criteria still block.\n- `spec new` / `spec approve` — the tool-agnostic authoring path (see the\n  spec-loop section above): scaffold a draft, fill it with any tool, land it\n  as the approved bundle with an attributed human approval, committed.\n  Unsigned local approvals are marked `identity_source: client`; cryptographic\n  signatures come from the governance service (license key).\n- `spec list` prints the approved acceptance criteria bundle: each story, its\n  criteria with check types, and the approver attribution. Read-only. Exit 0\n  on a valid bundle _or when none exists_; exit 2 on a malformed bundle (fail\n  closed on structure). `spec next` / `show` / `check` are the CLI twins of\n  the MCP bridge tools.\n\n### Badge\n\nShow visitors the repo is gated. `linebreak-gate badge` prints a ready-to-paste\nREADME snippet (no network calls — the shields.io static badge is fully encoded\nin its URL); `--format html|url` for the tag or bare-URL variants:\n\n```markdown\n[![gated by LineBreak](https://img.shields.io/badge/gated%20by-LineBreak-14120F?labelColor=FAF8F4)](https://www.linebreakapp.com/en/gate)\n```\n\n## Check scope: per story on PRs, full at release\n\nA team that approves the whole sprint up front (the flow this gate promotes:\nspec approved before code) would otherwise see every PR blocked by criteria of\nstories nobody has started. The fix is scope, not a weaker gate:\n\n- **Scan always.** The dependency and code scans run on every PR and on\n  release, unchanged.\n- **Check the story on PRs.** `linebreak-gate check --story <id>` evaluates\n  only that story's criteria (`--story` repeats). `--started-only` evaluates\n  only stories whose local state is `doing`, `review`, or `done` (the state\n  `spec next` and the MCP bridge write); stories without a state are listed as\n  not started and do not count. When no story is started at all (no state\n  file, an unreadable one, or an external tracker without local states) the\n  scope selects nothing and the check is exit 2, never a vacuous pass.\n  `--manual warn` reports `manual` criteria\n  without a sign-off as pending instead of blocking, so a sign-off that\n  belongs to the release does not hold a PR.\n- **Check everything at release.** The release job runs the full bundle with\n  `--manual block` (the default): every criterion of every story, every\n  `manual` criterion signed off. Every run writes\n  `.linebreak/audit/criteria.json` stamped with its `scope` and\n  `pending_signoffs`, so a scoped or relaxed run is evidence of that run and\n  can never be read as a full verdict (and CI never uploads a stale one).\n\nThe summary prints a `scope:` line (mode, stories evaluated, criteria counted,\nmanual policy) and one `pending sign-off:` line per missing sign-off; the JSON\ncarries the same under `scope` and `pending_signoffs`. An unknown `--story` id\nis exit 2 (a scope that names nothing is a mistake, never a pass).\n\nIn the GitHub Action the same pattern is two inputs. `story` is `all` (every\nstory, the default), `auto` (infer the id from a `feat/<id>` or `story/<id>`\nbranch, a trailing slug allowed as in `feat/<id>-add-login`, when it is an\napproved story; otherwise started stories only), or an explicit id. `manual`\nis `warn` or `block`; left empty it is `warn` on `pull_request` and `block` on\nevery other event. The PR comment shows the resolved scope, the stories not\nstarted, and the pending sign-offs.\n\n**Behavior change for existing `@v1` users (1.11.0):** the `manual` default on\n`pull_request` events is now `warn`, so a `manual` criterion without a\nsign-off no longer blocks a PR unless the workflow sets `manual: block`. Add\nthe release job below (or set `manual: block` on the PR job) to keep\nsign-offs enforced.\n\n```yaml\n# .github/workflows/security-gate.yml, PR gate + release gate\nname: Security gate\non:\n  pull_request:\n  push:\n    tags: [\"v*\"] # the release job runs on release tags\n\npermissions:\n  contents: read\n  pull-requests: write\n\njobs:\n  gate:\n    if: github.event_name == 'pull_request'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v5\n      - uses: Baktun-Studio/linebreak-gate@v1\n        with:\n          license-key: ${{ secrets.LINEBREAK_LICENSE_KEY }}\n          story: auto # this PR's story, or started stories only\n          manual: warn # sign-offs are listed, not blocking, on PRs\n\n  release-gate:\n    if: startsWith(github.ref, 'refs/tags/v')\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v5\n      - uses: Baktun-Studio/linebreak-gate@v1\n        with:\n          license-key: ${{ secrets.LINEBREAK_LICENSE_KEY }}\n          story: all # every story, every criterion\n          manual: block # every manual criterion needs its sign-off\n```\n\nRequire the `gate` check on the default branch and the `release-gate` job\nbefore publishing. Generic CI: the same two invocations of the CLI, with the\nexit codes respected.\n\n## Configuration — `.linebreak/gate.yml`\n\nThe gate's strictness is governance, so it lives in the repo — changing the\nthreshold is itself a PR: visible, reviewable, attributable in git history.\n\n```yaml\n# .linebreak/gate.yml\nfail_on: critical # critical (default) | high | medium | low\nexclude_paths: # optional: root-relative globs excluded from scanning\n  - fixtures\n  - \"sandbox/*\"\ncode_scan: auto # auto (run when model credentials are set) | on (required) | off\ncriteria:\n  enforce: true # default: true whenever a spec bundle exists; false disables\n  # criteria checking only (the security scan is unaffected)\n```\n\nPrecedence: explicit `--fail-on` flag / Action input → `.linebreak/gate.yml` →\nbuilt-in default (`critical`). An invalid config is a tool error (exit 2) —\na broken governance file never silently falls back to a default.\n\n## Audit records\n\nEvery scan and every override is recorded in `.linebreak/audit/security.json`\n(dependencies) and `.linebreak/audit/code.json` (AI SAST) — the same versioned\ndocument format the LineBreak tools write, carrying findings (CVE id,\nCVSS, advisory link), scanner engine, timestamp, actor, and the approval trail\nwith each override's reason + approver. Who relaxed the gate, and when, is\nitself auditable.\n\n## Pricing\n\n**Free, forever:** the dependency CVE scan and the whole spec loop — authoring,\nhuman approval, MCP serving, and CI enforcement. No key, no account.\n\n**Pro — $99/month per team** ([pricing](https://www.linebreakapp.com/en/pricing)):\ncryptographically **signed, tamper-evident approvals** (Ed25519, verifiable\noffline), required-key enforcement mode, and **hosted AI code review** with no\nAPI key to manage. Buy on the pricing page — your `LINEBREAK_LICENSE_KEY`\narrives by email within seconds (it's the Action's `license-key` input).\nPrefer your own model key? `ANTHROPIC_API_KEY` also enables the AI review;\nPro's hosted review is the zero-config path.\n\nThe gate runs **open** by default: it works without a key and prints a notice\nwhen no `LINEBREAK_LICENSE_KEY` is set (suppressed for BYOK users). That's\nfreemium — the dependency scan runs free. Teams that want to _require_ a valid\nPro key for the gate to run at all can opt into\n`LINEBREAK_ENTITLEMENTS_PROVIDER=remote`, which checks the entitlement **before**\nany scan and fails closed on a missing/invalid/revoked key, wrong plan, or\nunreachable service — blocking the whole gate, dependency scan included.\n",
  "bytes": 17356,
  "sha": "da0e357b87501f4b75dd0804529144d58639d2bbc8b823f48b8195e60f630bb5",
  "repo_slug": "baktun-studio/linebreak-gate",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_com_linebreakapp_linebreak_gate_a38198b0/readme"
}