> ## Documentation Index
> Fetch the complete documentation index at: https://docs.decimal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Fixing a blocked publish

> Every reason the registry can refuse a publish — what each one means, the exact fix, and how to clear it before your launch moment.

You tried to publish a skill and the registry refused. That's **SkillSafety** doing its job: the same review that stamps a public safety band (Passed / Caution / Blocked / Not-yet-reviewed) also gates the publish itself. Almost every refusal is a fixable finding, not a dead end — the two exceptions are called out below.

This page maps every refusal reason to what it means and exactly how to clear it.

## The order the gates run

Publish runs four gates in sequence. The first one that fails is the reason you see — fix it, re-publish, and the next gate runs.

```mermaid theme={null}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#f5f5f4','primaryBorderColor':'#a8a29e','primaryTextColor':'#44403c','lineColor':'#a8a29e'}}}%%
flowchart LR
  A["Benchmark<br/>presence"] --> B["Tier-1<br/>static scan"]
  B --> C["Tier-2<br/>AI security review"]
  C --> D["Tier-3<br/>content safety"]
  D --> E["Published"]
```

| Order | Gate                                                               | Refusal reason                                                        |
| :---: | ------------------------------------------------------------------ | --------------------------------------------------------------------- |
|   1   | **Benchmark presence** — an eval suite + a completed benchmark run | *see [Community Registry](/guides/registry#4-publish-your-own-skill)* |
|   2   | **Tier-1** — deterministic static scan (no LLM, free, instant)     | `safety_blocked`                                                      |
|   3   | **Tier-2** — AI security review (intent judge)                     | `intent_rejected`                                                     |
|   4   | **Tier-3** — content-safety review                                 | `content_blocked` · `content_removed` · `content_unverified`          |

<Note>
  The publish gate itself is **always free** — you never spend quota to attempt a publish, no matter how many times you retry.
</Note>

## Reason → meaning → fix

| Reason               | Band                   | What it means                                                                                                                                                                                                                                     | How to fix                                                                                                                                                                 |
| -------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `safety_blocked`     | **Blocked** (hidden)   | Tier-1 found a **critical** pattern in the exact body you're publishing — a live secret, a remote-code-execution or reverse-shell instruction, a data-exfiltration step, agent-config snooping, hidden unicode, and so on.                        | Open the findings modal. Each finding shows the **check**, the **line**, the **evidence**, and a **fix**. Apply the fix per finding, then **Re-run checks** or re-publish. |
| `intent_rejected`    | **Blocked** (hidden)   | Tier-2's intent judge read the skill as a whole and concluded its *purpose* is to get an agent to do something unsafe — often fluent prose a regex can't catch (a fake "prerequisite" step that fetches and runs a remote script).                | Read the judge's rationale, remove the manipulative instruction, and re-publish. If it's a false read on legitimate security content, see the context note below.          |
| `content_blocked`    | **Held**               | Tier-3 found prohibited **published text** — hate, graphic violence, sexual content, self-harm, illegal goods, doxxing/PII, or credible threats — in a category that is remediable. Content-flagged skills are *held*, not listed with a warning. | Remove or rewrite the offending text. Any illustrative example must be **synthetic**. Re-publish to re-run Tier-3.                                                         |
| `content_removed`    | **Blocked** (terminal) | Tier-3 matched a **terminal** category — CSAM or a credible threat. This is not remediable by editing.                                                                                                                                            | None. The skill is removed and cannot be re-published.                                                                                                                     |
| `content_unverified` | **Not yet reviewed**   | A reviewer was briefly unavailable, so the content check hasn't completed. This is **fail-open** — never a false block.                                                                                                                           | Nothing required. It's re-checked automatically. You can re-publish to re-trigger the check immediately.                                                                   |

<Warning>
  `content_removed` is the one terminal outcome. **CSAM and credible threats** are removed, not returned for editing — there is no fix-and-retry loop for these categories.
</Warning>

## `safety_blocked` — Tier-1 static scan

Tier-1 is pure text analysis: regex and structural checks, no LLM, run instantly and free on every publish. It groups its checks into four families.

| Family                 | Catches                                                                                                                                                                                                                  |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Instructions**       | Prompt-injection phrasing, anti-refusal / jailbreak language, trigger-abuse                                                                                                                                              |
| **Commands**           | Remote-code-execution, reverse-shell, destructive commands, download-and-execute                                                                                                                                         |
| **Data & credentials** | Committed secrets, data-exfiltration, agent-snooping (reading `.claude` / `.codex` / `.gemini` / `mcp.json`), cloud-metadata / SSRF, opaque payloads, hidden unicode, look-alike (homoglyph) characters, suspicious URLs |
| **Tools**              | Over-broad `allowed-tools`                                                                                                                                                                                               |

The findings modal is built to be actioned line by line. For each critical finding you get:

* **Check** — which rule fired (e.g. `data-exfiltration`)
* **Line** — where in the body it matched
* **Evidence** — the offending snippet, with any **secret redacted** — the scanner never echoes a credential back to you
* **Fix** — the concrete change that clears it

<Tip>
  Tier-1 is **context-aware**. A skill that legitimately *documents* an attack — one filed under a security category, or a fenced code block marked with `example` / `detect` / `never` — is **downgraded, not blocked**. If your security skill is getting flagged, add those markers so the scanner can tell teaching from doing.
</Tip>

## `intent_rejected` — Tier-2 AI security review

Where Tier-1 reads patterns, Tier-2 reads **intent**. An LLM judge evaluates what the skill is actually trying to make an agent do and returns `safe` / `review` / `reject`. A `reject` becomes `intent_rejected`.

This tier exists to catch what a regex structurally can't: fluent, well-written social engineering. The classic case is a skill with a friendly **"Prerequisites"** section that instructs the agent to `curl` a URL and pipe it to a shell before doing anything useful — every individual line looks benign, but the intent is to fetch-and-run attacker code.

To fix: read the judge's rationale, cut the instruction that steers the agent toward the unsafe action, and re-publish. If you believe the skill is legitimate security tooling, apply the same **example / detect / never** markers and security-category framing that Tier-1 respects — the judge weighs framing too.

## `content_blocked` / `content_removed` / `content_unverified` — Tier-3 content safety

Tier-3 asks a different question from the first two tiers: not *is this skill dangerous to run*, but *does the published text itself carry prohibited content*. An LLM reviews the body against these categories:

* Hate
* Graphic violence
* Sexual content / CSAM
* Self-harm
* Illegal goods
* Doxxing / PII
* Credible threats

Two rules to remember:

1. **Examples must be synthetic.** If your skill needs to show a sample email, sample PII, or sample abusive message, fabricate it. Real personal data trips the doxxing/PII check.
2. **Two categories are terminal.** **CSAM** and **credible threats** produce `content_removed` — the skill is taken down and cannot be re-published. Every other category is remediable: edit the text and re-publish.

`content_unverified` is not a violation at all — it's the fail-open state when a reviewer was momentarily unavailable. The skill shows **Not yet reviewed** and is re-checked automatically. You never get a false block from a reviewer outage.

## The remediation loop

Every refusal returns **structured findings, each with its own fix**. The loop is short:

<Steps>
  <Step title="Fix the body">
    Apply the per-finding fix from the modal — remove the secret, rewrite the manipulative step, replace real PII with synthetic, add `example` / `detect` / `never` markers to legitimate security content.
  </Step>

  <Step title="Re-run checks (free, Tier-1 only)">
    The **Re-run checks** button re-runs the Tier-1 static scan on any skill you own — no publish required, no quota spent. Use it to confirm you cleared a `safety_blocked` finding before you attempt the full publish.
  </Step>

  <Step title="Re-publish (re-runs all three gates)">
    Publishing re-runs Tier-1, Tier-2, and Tier-3 in order. The publish attempt is always free, so there's no cost to iterating.
  </Step>
</Steps>

<Note>
  **Re-run checks** covers Tier-1 only — the deterministic scan is free to run as often as you like. The LLM tiers (Tier-2 and Tier-3) run at publish time, or on demand via **Deep review** below.
</Note>

## Deep review — clear the LLM tiers before your launch

The publish gate runs Tier-2 and Tier-3 at the moment you publish. If you'd rather not discover an `intent_rejected` or `content_blocked` *during* your launch, run those LLM tiers ahead of time against a **private draft** with **Deep review**. It runs the same Tier-2 + Tier-3 checks on an unpublished skill so you can fix findings on your own schedule.

Deep review is metered. Each plan gets a monthly quota:

|                      | Free | Core |  Pro  | Enterprise |
| -------------------- | :--: | :--: | :---: | :--------: |
| Deep reviews / month |  10  |  100 | 1,000 |    5,000   |

<Note>
  The quota applies only to **Deep review** — the on-demand LLM run against a private draft. The **publish gate itself is always free**, and so is the Tier-1 **Re-run checks** button. Deep review buys you the LLM verdict *before* the launch moment; it doesn't gate publishing.
</Note>

## Catch it locally, before the server ever sees it

The **same scanner** that powers Tier-1 runs on your machine — free, no API key, and nothing leaves your laptop. Run it in your editor or wire it into CI so a `safety_blocked` never reaches a publish attempt.

<CodeGroup>
  ```bash decimalai CLI theme={null}
  # Scan a skills directory; exit 1 if anything is blocked
  decimalai skills scan ./skills
  ```

  ```bash skillevaluation theme={null}
  # Same scanner, from the skillevaluation package
  skillevaluation scan ./skills
  ```

  ```yaml GitHub Action theme={null}
  # Runs on every PR; uploads SARIF to code scanning
  - name: SkillSafety scan
    run: decimalai skills scan ./skills --format sarif > results.sarif
  - uses: github/codeql-action/upload-sarif@v3
    with:
      sarif_file: results.sarif
  ```
</CodeGroup>

Output formats: `--format text | json | github | sarif`. Blocked findings exit `1`, so the scan fails your build. `sarif` uploads straight to GitHub code scanning.

<Warning>
  The local scan reads **only the frontmatter** — it can't see everything the server sees, so it's deliberately allowed to be **stricter** than the publish gate, never looser. Treat a clean local scan as advisory: it means you've cleared the obvious Tier-1 findings, not that the server-side gate will pass.
</Warning>

## When a live skill goes bad

<Note>
  Review doesn't stop at publish. Every version carries its own scan and verdict history, and a **real adverse verdict on an already-published skill de-lists it** — the skill drops out of the registry and the owner gets an **email** that the band worsened. If you own a published skill, watch for that mail; it means a re-check found something the original publish didn't.
</Note>

## Related

<CardGroup cols={3}>
  <Card title="Community Registry" icon="store" href="/guides/registry">
    Publishing, forking, and the benchmark-presence gate that runs before SkillSafety.
  </Card>

  <Card title="SkillScore" icon="gauge-high" href="/guides/skillscore">
    The effectiveness band that sits beside SkillSafety on every skill.
  </Card>

  <Card title="skillevaluation" icon="flask" href="/guides/skillevaluation">
    The package that ships the `scan` command and the A/B benchmark.
  </Card>
</CardGroup>
