feat: migrate skills review desk to astro
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
---
|
||||
name: confluence-page
|
||||
description: Create or update a Confluence page on BASS from a local storage-format draft, using mcp-atlassian. Use when scaffolding a new page in AVP or BASS, mirroring a doc into a space, or updating an existing page by id or by space+title.
|
||||
---
|
||||
|
||||
# Confluence Page
|
||||
|
||||
Draft a page in storage format locally, lint it, then post or update it via
|
||||
`mcp-atlassian`. The skill never edits a page in place without a draft file on
|
||||
disk and a pre-flight pass.
|
||||
|
||||
Canonical source: [BASS Confluence](https://bass.netcracker.com). When the
|
||||
skill and a BASS page disagree, BASS wins and this skill gets updated.
|
||||
|
||||
## Hard rules
|
||||
|
||||
- **Storage format, not wiki markdown.** Confluence Cloud expects the
|
||||
`body.storage` representation. Wiki markup only renders correctly when the
|
||||
page's renderer is configured for it; do not assume.
|
||||
- **No secrets, tokens, customer PII, or session cookies** in any body.
|
||||
`references/secrets.md` lists the patterns to scrub.
|
||||
- **Title is unique within the parent** — verify with `confluence_search` or
|
||||
`confluence_get_page(spaceKey, title)` before creating.
|
||||
- **PlantUML goes through the `{plantuml}` macro** at body root, never inside
|
||||
an info panel or a code block — see `diagram-plantuml` skill.
|
||||
- **Attachments go through the attachments API**, not as base64 in the body.
|
||||
See `references/attachments.md`.
|
||||
- **One page per draft file.** Don't stuff multiple pages into one storage file;
|
||||
split before posting.
|
||||
|
||||
## Workflow: new page
|
||||
|
||||
1. Pick a template from `templates/` and copy it to a scratch file under
|
||||
`~/Netcracker/Projects/NDO/knowledge/confluence/drafts/<SPACE>/<slug>.xml`
|
||||
(`<SPACE>` is the space key, e.g. `AVP`, `BASS`).
|
||||
2. Decide the parent. Default parent is the space home for top-level pages.
|
||||
Use `confluence_search` to find the parent id when nesting.
|
||||
3. Fill the body. Storage format uses standard XHTML; the only macros that
|
||||
survive the round trip are listed in `references/macros.md`.
|
||||
4. Run `scripts/dry-run-publish.sh <draft>` — it lints the body, runs the
|
||||
`unslop` pass, and verifies every `{plantuml}` block parses.
|
||||
5. `mcp__atlassian.confluence_create_page(spaceKey, title, storageFilePath,
|
||||
parentId?)` to post. The MCP tool reads the file directly; never paste the
|
||||
body into the call.
|
||||
6. Capture the new page id in `~/Netcracker/Projects/NDO/knowledge/confluence/_index.md`
|
||||
so it appears in the local mirror index.
|
||||
|
||||
## Workflow: update existing page
|
||||
|
||||
1. Resolve the page id. `confluence_get_page(spaceKey, title)` if you know the
|
||||
title, otherwise `confluence_search(cql="title=\"…\"")`.
|
||||
2. Fetch the current storage body with `confluence_get_page_content(pageId)`
|
||||
and save it next to your draft under
|
||||
`confluence/drafts/<SPACE>/<slug>.from-server.xml`. This is your safety net.
|
||||
3. Diff your draft against the server copy. If a section was renamed upstream
|
||||
but is still wanted locally, carry the change forward; if it was deleted,
|
||||
drop it.
|
||||
4. Run `scripts/dry-run-publish.sh <draft>`.
|
||||
5. `mcp__atlassian.confluence_update_page_from_file(pageId, storageFilePath,
|
||||
title?, minorEdit=true, versionMessage="…")`. Default `minorEdit` to true;
|
||||
only set false for content rewrites.
|
||||
6. If the diff touched more than the section you set out to change, stop and
|
||||
re-pull the page before posting.
|
||||
|
||||
## Workflow: mirror a markdown file into Confluence
|
||||
|
||||
1. Run the page-reviewer skill first. Mirrors must not introduce slop into a
|
||||
governed space.
|
||||
2. Convert headings from `#`/`## `###` to `h1`/`h2`/`h3`. Strip any leading
|
||||
front-matter — the storage body must not contain `---` fences.
|
||||
3. Strip any path that leaks the local mirror root
|
||||
(`/home/masi1023/Netcracker/Projects/NDO/knowledge/...`). Use the public
|
||||
BASS URL instead.
|
||||
4. Convert `[[wikilinks]]` to plain text or proper Confluence links; the wiki
|
||||
linker only resolves inside BASS.
|
||||
5. Convert fenced code blocks to `<ac:structured-macro
|
||||
ac:name="code"><ac:parameter ac:name="language">…</ac:parameter><ac:plain-text-body><![CDATA[ … ]]></ac:plain-text-body></ac:structured-macro>`.
|
||||
6. Run the dry-run script.
|
||||
|
||||
## Body format cheatsheet
|
||||
|
||||
The MCP server expects a UTF-8 file containing a fragment of storage XHTML.
|
||||
Common elements:
|
||||
|
||||
| You want | Storage format |
|
||||
|----------|----------------|
|
||||
| Heading | `<h2>…</h2>` |
|
||||
| Paragraph | `<p>…</p>` |
|
||||
| Bold / italic | `<strong>…</strong>` / `<em>…</em>` |
|
||||
| List | `<ul><li>…</li></ul>` / `<ol><li>…</li></ol>` |
|
||||
| Table | `<table><tbody><tr><th>…</th><td>…</td></tr></tbody></table>` |
|
||||
| Info panel | `<ac:structured-macro ac:name="info"><ac:rich-text-body>…</ac:rich-text-body></ac:structured-macro>` |
|
||||
| Code block | `<ac:structured-macro ac:name="code" ac:name="language">…</ac:structured-macro>` |
|
||||
| PlantUML | `<ac:structured-macro ac:name="plantuml"><ac:plain-text-body><![CDATA[@startuml … @enduml]]></ac:plain-text-body></ac:structured-macro>` |
|
||||
| Link | `<a href="https://…">label</a>` |
|
||||
| Page link | `<ac:link><ri:page ri:content-title="…"/></ac:link>` |
|
||||
|
||||
Full macro catalog: [references/macros.md](references/macros.md).
|
||||
|
||||
## Picking the parent page
|
||||
|
||||
- Top-level page under the space home: omit `parentId` (MCP defaults to the
|
||||
space home) or pass the space home id explicitly.
|
||||
- Nested under a hub or domain page: find the parent id with
|
||||
`confluence_search(cql="space=AVP AND title~\"Hub\"")` and pick by hand.
|
||||
- Moving a page later is a separate API call; do not "fix" the parent by
|
||||
deleting and recreating — that loses history, watchers, and reactions.
|
||||
|
||||
## Picking the space
|
||||
|
||||
| Content kind | Space |
|
||||
|--------------|-------|
|
||||
| NDO product docs | `AVP` |
|
||||
| Internal team / governance / how-to | `BASS` |
|
||||
| Customer-facing release notes | check with the page owner |
|
||||
| Personal scratch | do **not** post to BASS / AVP; keep in `~/Netcracker/Projects/NDO/knowledge/` |
|
||||
|
||||
If unsure, ask before posting.
|
||||
|
||||
## MCP availability
|
||||
|
||||
`mcp-atlassian` is listed in the
|
||||
[BASS Cursor MCPs approval page](https://bass.netcracker.com/display/~seby0316/Cursor+-+MCPs+approval+status)
|
||||
as *Not approved* by default — that page was last synced 2026-06-11; check the
|
||||
current status before relying on it. The skill assumes the MCP server is wired
|
||||
into the active Claude / Cursor client. Run `scripts/check-mcp-atlassian.sh`
|
||||
to detect it and get an install hint if missing.
|
||||
|
||||
## Safety
|
||||
|
||||
- **Read-only on `~/Netcracker/Projects/NDO/knowledge/confluence/<SPACE>/`.**
|
||||
Mirrors are snapshots. Never edit them in place — re-pull instead.
|
||||
- **Drafts live under `confluence/drafts/`** and are the only files this
|
||||
skill writes to by default.
|
||||
- **No page deletion** through this skill. Deletes are not undoable and lose
|
||||
history. If a page must go, ask in the page's comments first.
|
||||
- **Never paste body content into the API call** — pass a file path so the
|
||||
body stays reviewable in git.
|
||||
|
||||
## Related
|
||||
|
||||
| Skill | Role |
|
||||
|-------|------|
|
||||
| `page-reviewer` | Mandatory pre-post gate; runs before any create/update |
|
||||
| `unslop` | Removes AI phrasing so the page reads as Netcracker voice |
|
||||
| `diagram-plantuml` | Owns the `{plantuml}` macro and the diagram macro catalog |
|
||||
| `confluence-to-slides` (existing) | Pulls a finished page into a slide deck |
|
||||
@@ -0,0 +1,68 @@
|
||||
# Attachments
|
||||
|
||||
Attachments live on a page and are referenced by filename. They survive page
|
||||
moves and template changes, but they do not survive page deletion.
|
||||
|
||||
## Upload via mcp-atlassian
|
||||
|
||||
```python
|
||||
mcp__atlassian.confluence_upload_attachment(
|
||||
pageId=…,
|
||||
filePath="path/to/file.png",
|
||||
comment="optional version note",
|
||||
)
|
||||
```
|
||||
|
||||
Returns a metadata object including the download URL. Use that URL inside the
|
||||
page body, not a local file path.
|
||||
|
||||
## Reference in the body
|
||||
|
||||
By attachment filename:
|
||||
|
||||
```xml
|
||||
<ac:link>
|
||||
<ri:attachment ri:filename="diagram.png" />
|
||||
<ac:plain-text-link-body><![CDATA[diagram]]></ac:plain-text-link-body>
|
||||
</ac:link>
|
||||
```
|
||||
|
||||
As an inline image:
|
||||
|
||||
```xml
|
||||
<ac:image ac:width="600">
|
||||
<ri:attachment ri:filename="diagram.png" />
|
||||
</ac:image>
|
||||
```
|
||||
|
||||
Always set `ac:alt` for accessibility:
|
||||
|
||||
```xml
|
||||
<ac:image ac:width="600">
|
||||
<ri:attachment ri:filename="diagram.png" />
|
||||
<ac:alt>Sequence diagram of the order → inventory → shipment flow.</ac:alt>
|
||||
</ac:image>
|
||||
```
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- Don't paste base64 PNG into the body. The page editor can't replace it
|
||||
without re-rendering the whole page; it bloats the storage body; the page
|
||||
cannot be reviewed by lint.
|
||||
- Don't link to a public CDN. BASS pages are private; CDN URLs leak and break
|
||||
on access-controlled spaces.
|
||||
- Don't re-upload the same file under a new name. Confluence deduplicates by
|
||||
hash within a page, but the editor doesn't surface duplicates well.
|
||||
|
||||
## Versioning
|
||||
|
||||
Attach with a version suffix (`diagram-v2.png`) when updating. Confluence
|
||||
keeps the old version in the attachments list and the page body continues to
|
||||
reference the filename; change the filename in the body to point at the new
|
||||
version.
|
||||
|
||||
## Cleanup
|
||||
|
||||
Pages with stale attachments show up in the space's attachment report. When
|
||||
removing a diagram, also remove the attachment (do not leave orphaned files
|
||||
on the page).
|
||||
@@ -0,0 +1,112 @@
|
||||
# Confluence Storage Macros
|
||||
|
||||
Confluence Cloud storage format accepts a fixed set of macros. Anything not in
|
||||
this catalog either renders as plain text or fails silently. Before adding a
|
||||
new macro to a draft, check the name here.
|
||||
|
||||
## Inline
|
||||
|
||||
| Macro | When |
|
||||
|-------|------|
|
||||
| `{code}` | Fenced code with optional language |
|
||||
| `{plantuml}` | Diagrams — see `diagram-plantuml` skill |
|
||||
| `{info}` | Info panel |
|
||||
| `{note}` | Note panel |
|
||||
| `{warning}` | Warning panel |
|
||||
| `{tip}` | Tip panel |
|
||||
| `{excerpt}` | Reusable fragment; also `excerpt-include` |
|
||||
| `{anchor}` | Inline anchor for `{pageref}` |
|
||||
| `{pageref}` | Cross-page reference by anchor |
|
||||
| `{children}` | Lists child pages |
|
||||
| `{include}` | Includes another page (full or excerpt) |
|
||||
| `{table-of-content}` | Outline from heading hierarchy |
|
||||
| `{expand}` | Collapsible section |
|
||||
| `{status}` | Coloured status pill |
|
||||
| `{cheese}` | Image gallery — prefer `image` element instead |
|
||||
| `{noformat}` | Plain monospace, no language hint |
|
||||
|
||||
## Panels
|
||||
|
||||
Panels take rich-text bodies. PlantUML inside a panel does not render — put
|
||||
diagrams at body root.
|
||||
|
||||
```xml
|
||||
<ac:structured-macro ac:name="info">
|
||||
<ac:rich-text-body>
|
||||
<p>Body goes here.</p>
|
||||
</ac:rich-text-body>
|
||||
</ac:structured-macro>
|
||||
```
|
||||
|
||||
Available panel macros: `info`, `note`, `warning`, `tip`, `success`,
|
||||
`error`, `panel` (generic).
|
||||
|
||||
## Code block
|
||||
|
||||
```xml
|
||||
<ac:structured-macro ac:name="code">
|
||||
<ac:parameter ac:name="language">python</ac:parameter>
|
||||
<ac:parameter ac:name="title">example.py</ac:parameter>
|
||||
<ac:parameter ac:name="linenumbers">true</ac:parameter>
|
||||
<ac:plain-text-body><![CDATA[def hello():
|
||||
pass]]></ac:plain-text-body>
|
||||
</ac:structured-macro>
|
||||
```
|
||||
|
||||
`language` accepts the short names from Confluence's language list (`python`,
|
||||
`java`, `javascript`, `typescript`, `go`, `bash`, `sql`, `json`, `yaml`,
|
||||
`xml`, `markdown`). Anything outside the list falls back to plain monospace.
|
||||
|
||||
## Tables
|
||||
|
||||
Standard XHTML tables. Confluence does not need the `<ac:structured-macro
|
||||
ac:name="table">` wrapper for plain tables.
|
||||
|
||||
```xml
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Column A</th>
|
||||
<th>Column B</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>cell</td>
|
||||
<td>cell</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
```
|
||||
|
||||
For sortable or filterable tables, use the `table-plus` macro — but only
|
||||
when the table is genuinely worth the overhead.
|
||||
|
||||
## Links
|
||||
|
||||
- External: `<a href="https://…">label</a>`
|
||||
- Page by title: `<ac:link><ri:page ri:content-title="Hub"/></ac:link>`
|
||||
- Page by id: `<ac:link><ri:page ri:content-id="12345"/></ac:link>`
|
||||
- Attachment: `<ac:link><ri:attachment ri:filename="diagram.png"/></ac:link>`
|
||||
- User mention: `<ac:link><ri:user ri:username="marcos"/></ac:link>`
|
||||
|
||||
## Attachments
|
||||
|
||||
Attachments go through `mcp__atlassian.confluence_upload_attachment` /
|
||||
`confluence_create_page_from_file` (with the file path) — never as base64 in
|
||||
the body. See `attachments.md`.
|
||||
|
||||
## What is NOT a macro
|
||||
|
||||
| Construct | Status |
|
||||
|-----------|--------|
|
||||
| Wiki markup (`{code}…{code}`) | Renders only on pages whose renderer is set to wiki; do not assume |
|
||||
| Markdown fences | Not interpreted; render as text |
|
||||
| HTML5 `<details>` | Rendered as plain HTML; works but no styling |
|
||||
| Inline SVG | Works but is not editable through the page editor; prefer PlantUML |
|
||||
| `<script>` / `<iframe>` | Stripped by Confluence; do not bother |
|
||||
|
||||
## Naming conventions
|
||||
|
||||
- Macro names are lowercase.
|
||||
- Parameter names are lowercase with words separated by `-`, not `_`
|
||||
(`linenumbers`, not `line_numbers`).
|
||||
- Parameter values that include spaces must be quoted.
|
||||
@@ -0,0 +1,52 @@
|
||||
# Secrets and PII
|
||||
|
||||
A draft that contains any of the patterns below is **BLOCKED** by the
|
||||
`page-reviewer` skill. Scrub before posting; the reviewer's verdict is not
|
||||
overridden by "this is a test fixture" or "this is obvious from context".
|
||||
|
||||
## Hard blocks
|
||||
|
||||
| Pattern | Example | Action |
|
||||
|---------|---------|--------|
|
||||
| AWS access key id | `AKIA[0-9A-Z]{16}` | Replace with `<AWS_KEY>` |
|
||||
| AWS secret access key | `[A-Za-z0-9/+=]{40}` in env files | Replace with `<AWS_SECRET>` |
|
||||
| Bearer / personal token | `ghp_…`, `glpat-…`, `dapi…` | Replace with `<TOKEN>` |
|
||||
| Confluence / Jira token | `ATATT…` (Cloud), long base64 | Replace with `<CONFLUENCE_TOKEN>` |
|
||||
| Slack token | `xoxb-…`, `xoxp-…` | Replace with `<SLACK_TOKEN>` |
|
||||
| OpenAI key | `sk-…` (40+ chars after) | Replace with `<OPENAI_KEY>` |
|
||||
| Service-account password | any string in `*.password=…`, `secret: …` | Replace |
|
||||
| PEM private key | `-----BEGIN … PRIVATE KEY-----` | Replace |
|
||||
| Cookie value | `connect.sid=…`, `JSESSIONID=…` | Replace |
|
||||
|
||||
## Soft blocks (review)
|
||||
|
||||
| Pattern | Why | Action |
|
||||
|---------|-----|--------|
|
||||
| Customer email | PII | Mask: `j***@example.com` or remove |
|
||||
| Customer hostname / IP | PII + internal info | Replace with `<HOST>` / `<IP>` |
|
||||
| Runbook hostname (`*.k8s.sdntest.netcracker.com`) | Internal surface | Use the public URL or `<INTERNAL_HOST>` |
|
||||
| Phone number | PII | Mask or remove |
|
||||
| Bank / payment info | PII | Remove |
|
||||
|
||||
## Why this is in the skill
|
||||
|
||||
BASS Confluence is private to Netcracker, but watchers, exported PDFs, and
|
||||
incident write-ups leak. Pages are also exported to training data when teams
|
||||
mirror content into LLMs. "It's on a private space" is not enough.
|
||||
|
||||
## If you need a realistic-looking fixture
|
||||
|
||||
Generate one with the project's placeholder vocabulary:
|
||||
|
||||
- emails: `user1@example.com`, `user2@example.com`
|
||||
- IPs: `10.0.0.1`, `192.0.2.1`
|
||||
- tokens: `<TOKEN>`, `<SECRET>`
|
||||
- hostnames: `host-a.internal`, `host-b.internal`
|
||||
|
||||
Do not use the customer's name, the production hostname, or a real-looking
|
||||
token "because it doesn't matter".
|
||||
|
||||
## What the reviewer checks
|
||||
|
||||
The `page-reviewer` skill runs a grep pass against this list. A single hit
|
||||
returns **BLOCK**; the author fixes the draft and re-runs.
|
||||
@@ -0,0 +1,25 @@
|
||||
# BASS Space Keys
|
||||
|
||||
The BASS / AVP space keys used by `mcp__atlassian.confluence_*` calls.
|
||||
|
||||
| Space key | Name | Use it for |
|
||||
|-----------|------|------------|
|
||||
| `AVP` | NDO space | NDO product docs, hub pages, runbooks |
|
||||
| `BASS` | Netcracker Confluence | Internal team / governance / how-to / Cursor / MCP pages |
|
||||
| `NDO` | (legacy) | Old NDO content; new writes go to `AVP` |
|
||||
| `GF` | GFiber space | GFiber product content; the gfiber-logging skill targets here |
|
||||
| `NCM` | NCM space | NCM product content |
|
||||
| `~seby0316` | Personal space | Sebastián; the Cursor MCPs page lives here |
|
||||
|
||||
When in doubt, search for a similar page and use the same one. The mirror
|
||||
index at `~/Netcracker/Projects/NDO/knowledge/confluence/_index.md` lists the
|
||||
spaces already in use locally.
|
||||
|
||||
## Picking a space
|
||||
|
||||
- **Top-level product page** → the product space (`AVP` for NDO).
|
||||
- **Internal how-to / governance / Cursor / MCP** → `BASS`.
|
||||
- **Customer-facing release notes** → check with the page owner; the
|
||||
default is `doc.netcracker.com` not BASS.
|
||||
- **Personal scratch** → do not post to BASS / AVP; keep in
|
||||
`~/Netcracker/Projects/NDO/knowledge/confluence/drafts/`.
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
name: diagram-plantuml
|
||||
description: Embed PlantUML diagrams inside a Confluence page using the {plantuml} macro in the storage body. Use when a page needs a sequence, component, class, state, activity, deployment, or timing diagram and the macro name is not in the caller's muscle memory.
|
||||
---
|
||||
|
||||
# Diagram — PlantUML in Confluence
|
||||
|
||||
PlantUML renders server-side on the Confluence PlantUML plugin. The macro is
|
||||
`{plantuml}`, the body is plain PlantUML between `@startuml` and `@enduml`,
|
||||
and the host (BASS) renders it through the bundled plugin — no external URL
|
||||
needed for private spaces.
|
||||
|
||||
## Hard rules
|
||||
|
||||
- **Macro name is `plantuml`**, lowercase. `{PlantUML}` and `{plantUml}` both
|
||||
fail to render.
|
||||
- **Body goes inside `<ac:plain-text-body><![CDATA[ … ]]></ac:plain-text-body>`**,
|
||||
not inside `<ac:rich-text-body>`. The rich-text body treats the body as
|
||||
XHTML, which mangles `<`, `>`, and `&` that PlantUML relies on.
|
||||
- **Always include `@startuml` and `@enduml`** even though PlantUML accepts
|
||||
bodies without them. The Confluence renderer is stricter than the CLI.
|
||||
- **No diagram wider than ~900 px.** Confluence content columns are narrow;
|
||||
a wide diagram overflows on smaller screens. Split or simplify.
|
||||
- **No diagram inside an info / note / warning panel.** The renderer nests
|
||||
and crops. Put the diagram at body root, then put a `{tip}` after it with
|
||||
the takeaway.
|
||||
- **No diagram inside a code block.** Same nesting failure.
|
||||
- **Never paste a base64 PNG into the body** to skip PlantUML. If PlantUML
|
||||
can't render what you drew, simplify the diagram.
|
||||
|
||||
## Storage template
|
||||
|
||||
```xml
|
||||
<ac:structured-macro ac:name="plantuml">
|
||||
<ac:plain-text-body><![CDATA[@startuml
|
||||
!theme plain
|
||||
skinparam dpi 150
|
||||
|
||||
participant Client
|
||||
participant Service
|
||||
|
||||
Client -> Service: request
|
||||
Service --> Client: response
|
||||
@enduml]]></ac:plain-text-body>
|
||||
</ac:structured-macro>
|
||||
```
|
||||
|
||||
The `!theme plain` directive keeps diagrams legible on the BASS light
|
||||
background; the `skinparam dpi 150` is the right size for the Confluence
|
||||
column width. Drop both when a diagram already has its own `skinparam`
|
||||
block.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Decide the diagram type. See [references/diagram-types.md](references/diagram-types.md)
|
||||
for the cheat sheet (sequence, component, class, state, activity,
|
||||
deployment, timing, use case, ER, mindmap).
|
||||
2. Draft the PlantUML in a `.puml` scratch file. Run `plantuml -tpng -checkonly
|
||||
-failfast2 file.puml` if `plantuml` is on `$PATH` — fast feedback loop
|
||||
before posting.
|
||||
3. Wrap in the storage template above.
|
||||
4. Add a one-line caption directly after the macro using a `{tip}` block or
|
||||
a bolded sentence; do not rely on the title attribute (some renderers
|
||||
strip it).
|
||||
5. Hand the body to the `page-reviewer` skill. The reviewer re-runs the
|
||||
syntax check on every `{plantuml}` block.
|
||||
|
||||
## Common patterns
|
||||
|
||||
- **Sequence with notes:** use `note left of Alice: …` / `note right of
|
||||
Bob: …`. Inside an `alt`/`opt`/`loop` block, the note attaches to the
|
||||
branch.
|
||||
- **Component / C4:** use `!include <C4_Container>` only if the BASS PlantUML
|
||||
plugin has the C4 stdlib. If unsure, prefer hand-drawn `component` arrows.
|
||||
- **State:** use `state "Long label" as S1` to avoid breaking state names
|
||||
that contain spaces.
|
||||
- **Timing:** use `robust` for digital signals and `analog` for continuous;
|
||||
mixing them on one line is a render error.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Likely cause |
|
||||
|---------|--------------|
|
||||
| Macro renders as plain text | Macro name wrong, or the body is inside `<ac:rich-text-body>` instead of `<ac:plain-text-body>` |
|
||||
| Diagram renders empty | `@startuml / @enduml missing, or body has unescaped < / >` outside CDATA |
|
||||
| Diagram crops on the right | Width over the column budget — split or simplify |
|
||||
| Theme reverts to dark on dark space | Use `!theme plain` explicitly; some renderers ignore the page theme |
|
||||
| C4 include fails | Plugin doesn't ship the stdlib — switch to hand-drawn arrows |
|
||||
|
||||
Full troubleshooting table: [references/troubleshooting.md](references/troubleshooting.md).
|
||||
|
||||
## Related
|
||||
|
||||
| Skill | Role |
|
||||
|-------|------|
|
||||
| `confluence-page` | Owns the storage body; delegates diagrams here |
|
||||
| `page-reviewer` | Re-runs the syntax check on every `{plantuml}` block |
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
# PlantUML Diagram Types
|
||||
|
||||
The eight diagrams the Confluence page author reaches for, with the
|
||||
PlantUML skeleton for each. Pick the type by what the reader needs to
|
||||
*do* with the diagram, not by what the data looks like.
|
||||
|
||||
| Reader needs | Pick |
|
||||
|--------------|------|
|
||||
| Trace a request across actors | sequence |
|
||||
| Show who owns which service | component |
|
||||
| Show static structure / inheritance | class |
|
||||
| Show valid states of one object | state |
|
||||
| Show branching workflow | activity |
|
||||
| Show deployment topology | deployment |
|
||||
| Show signal timing / concurrency | timing |
|
||||
| Show domain entities | ER |
|
||||
|
||||
## Sequence
|
||||
|
||||
```
|
||||
@startuml
|
||||
participant Client
|
||||
participant Service
|
||||
participant DB
|
||||
|
||||
Client -> Service: request
|
||||
Service -> DB: query
|
||||
DB --> Service: rows
|
||||
Service --> Client: response
|
||||
@enduml
|
||||
```
|
||||
|
||||
## Component
|
||||
|
||||
```
|
||||
@startuml
|
||||
[Web] --> [API]
|
||||
[API] --> [DB]
|
||||
[API] --> [Cache]
|
||||
@enduml
|
||||
```
|
||||
|
||||
For C4, prefer hand-drawn boxes if the BASS PlantUML plugin doesn't ship the
|
||||
`C4_Container` stdlib. Test with one diagram before committing to the
|
||||
notation.
|
||||
|
||||
## Class
|
||||
|
||||
```
|
||||
@startuml
|
||||
class Order {
|
||||
+id: UUID
|
||||
+status: Status
|
||||
+total(): Money
|
||||
}
|
||||
class LineItem {
|
||||
+sku: string
|
||||
+qty: int
|
||||
}
|
||||
Order "1" *-- "*" LineItem
|
||||
@enduml
|
||||
```
|
||||
|
||||
## State
|
||||
|
||||
```
|
||||
@startuml
|
||||
[*] --> Draft
|
||||
Draft --> Submitted: submit
|
||||
Submitted --> Approved: approve
|
||||
Submitted --> Rejected: reject
|
||||
Approved --> [*]
|
||||
Rejected --> [*]
|
||||
@enduml
|
||||
```
|
||||
|
||||
## Activity
|
||||
|
||||
```
|
||||
@startuml
|
||||
start
|
||||
:parse input;
|
||||
if (valid?) then (yes)
|
||||
:process;
|
||||
else (no)
|
||||
:reject;
|
||||
stop
|
||||
endif
|
||||
:persist;
|
||||
stop
|
||||
@enduml
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
```
|
||||
@startuml
|
||||
node "k8s prod" {
|
||||
[service-a] --> [service-b]
|
||||
}
|
||||
node "external" {
|
||||
[IdP]
|
||||
}
|
||||
[service-a] --> [IdP]
|
||||
@enduml
|
||||
```
|
||||
|
||||
## Timing
|
||||
|
||||
```
|
||||
@startuml
|
||||
robust "Client" as C
|
||||
robust "Service" as S
|
||||
C is Idle
|
||||
S is Idle
|
||||
@0
|
||||
C is Requesting
|
||||
@5
|
||||
S is Processing
|
||||
@10
|
||||
S is Idle
|
||||
C is Idle
|
||||
@enduml
|
||||
```
|
||||
|
||||
## ER
|
||||
|
||||
```
|
||||
@startuml
|
||||
entity "Order" {
|
||||
*id : UUID
|
||||
--
|
||||
total : Money
|
||||
}
|
||||
entity "LineItem" {
|
||||
*id : UUID
|
||||
--
|
||||
sku : string
|
||||
qty : int
|
||||
}
|
||||
Order ||--o{ LineItem : contains
|
||||
@enduml
|
||||
```
|
||||
|
||||
## What is NOT a use case
|
||||
|
||||
If the diagram needs prose between boxes, it is not a use case. Use a
|
||||
sequence or activity diagram instead.
|
||||
|
||||
## When to use multiple diagrams
|
||||
|
||||
A page that needs two diagrams is fine. A page that needs five is a wall
|
||||
— split the page.
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
# PlantUML Troubleshooting
|
||||
|
||||
Symptoms and fixes for the four classes of rendering failure on BASS
|
||||
Confluence.
|
||||
|
||||
## Macro renders as plain text
|
||||
|
||||
| Cause | Fix |
|
||||
|-------|-----|
|
||||
| Macro name wrong (`PlantUML`, `Plantuml`) | Use `plantuml`, lowercase |
|
||||
| Body inside `<ac:rich-text-body>` | Move to `<ac:plain-text-body>` |
|
||||
| Macro opened but not closed | Add the matching `</ac:structured-macro>` |
|
||||
| Page is in wiki renderer mode | Re-save in storage format (page properties → editor) |
|
||||
|
||||
## Diagram renders empty
|
||||
|
||||
| Cause | Fix |
|
||||
|-------|-----|
|
||||
| `@startuml` / `@enduml` missing | Add both, even if PlantUML accepts bodies without |
|
||||
| Body has unescaped `<` / `>` outside CDATA | Wrap entire body in `<![CDATA[ … ]]>` |
|
||||
| `!include` points to a stdlib the plugin doesn't ship | Replace with hand-drawn equivalent |
|
||||
| File-size limit exceeded (very large diagrams) | Split into multiple diagrams |
|
||||
|
||||
## Diagram crops on the right
|
||||
|
||||
| Cause | Fix |
|
||||
|-------|-----|
|
||||
| Width > ~900 px | Split the diagram horizontally into two, or simplify |
|
||||
| Long labels on long arrows | Shorten labels; move detail to body text |
|
||||
| Padding parameters set too high | Drop `skinparam Padding`, `skinparam Margin` overrides |
|
||||
|
||||
## Theme reverts to dark on dark space
|
||||
|
||||
| Cause | Fix |
|
||||
|-------|-----|
|
||||
| Page theme overrides the diagram theme | Use `!theme plain` explicitly at the top of the body |
|
||||
| BASS theme override | Hard-code colors with `skinparam` per element |
|
||||
|
||||
## C4 / standard library includes fail
|
||||
|
||||
| Cause | Fix |
|
||||
|-------|-----|
|
||||
| Plugin doesn't ship the stdlib | Switch to `component` diagram or hand-drawn boxes |
|
||||
| Include URL is blocked by network policy | Mirror the stdlib locally, use `!include /path/to/C4_Container.puml` (only if the plugin supports it) |
|
||||
|
||||
## Debugging loop
|
||||
|
||||
1. Save the `.puml` body to a file.
|
||||
2. Run `plantuml -tpng -checkonly -failfast2 file.puml`.
|
||||
3. If local parse fails, the body is wrong — fix the syntax.
|
||||
4. If local parse succeeds but Confluence fails, the wrapper is wrong — fix
|
||||
the storage macro form.
|
||||
|
||||
## When to give up on PlantUML
|
||||
|
||||
- The diagram needs interactivity (hover, click). Confluence PlantUML does
|
||||
not support this.
|
||||
- The diagram needs real images (logos, photos). Drop them in via attachment
|
||||
instead.
|
||||
- The diagram needs to be edited by non-technical authors. PlantUML is not
|
||||
the right tool.
|
||||
|
||||
## When to escalate
|
||||
|
||||
- The BASS plugin version changes and breaks a working diagram. Capture the
|
||||
diff, fix the diagram, and update this troubleshooting page.
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
name: page-reviewer
|
||||
description: Audit a Confluence-ready body before it is posted or updated. Use as the last gate before confluence_create_page_from_file or confluence_update_page_from_file; do not post a page that has not been through this skill.
|
||||
---
|
||||
|
||||
# Page reviewer
|
||||
|
||||
A Confluence page is hard to walk back once it's live: watchers, reactions,
|
||||
and links accumulate, and `minorEdit=true` will not save you from a body that
|
||||
embarrasses the team. Run this skill before every create or update.
|
||||
|
||||
The reviewer reads the draft and the page-context, and returns one of three
|
||||
verdicts:
|
||||
|
||||
- **PASS** — body is ready, post it
|
||||
- **REVISE** — specific, line-anchored changes are required before posting
|
||||
- **BLOCK** — something about the draft cannot be fixed locally (wrong space,
|
||||
wrong parent, scope creep, secret leak) — escalate
|
||||
|
||||
The reviewer never edits the draft. It returns a checklist; the human or the
|
||||
`confluence-page` skill applies the changes.
|
||||
|
||||
## Hard rules
|
||||
|
||||
- **No body that contains secrets, tokens, session cookies, customer PII, or
|
||||
internal hostnames** (`*.netcracker.com` internal suffixes are fine in
|
||||
links; IPs, hostnames and ports from runbooks are not). The reviewer
|
||||
blocks on first match.
|
||||
- **No body that references the local mirror path** (`~/Netcracker/Projects/NDO/knowledge/...`).
|
||||
Use the public BASS URL.
|
||||
- **No body larger than 300 lines** without a one-line reason in the draft
|
||||
header. Pages drift; reviewers and readers both lose when they do.
|
||||
- **No body whose title collides with an existing page** under the same
|
||||
parent — see step 2 of the workflow.
|
||||
- **No unrendered macros** — every `{plantuml}`, `{code}`, `{info}`, `{note}`,
|
||||
`{warning}` block must be in its proper storage form (see
|
||||
`confluence-page/references/macros.md`). The reviewer rejects raw wiki
|
||||
markup and raw Markdown inside storage bodies.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Identify the page.** Title, parent, space key, target id (for update).
|
||||
2. **Collision check.** If creating:
|
||||
- `mcp__atlassian.confluence_search(cql="space=<SPACE> AND title~\"<title>\"")`
|
||||
- If a page already exists under the same parent, return **BLOCK** with
|
||||
"title collision — pick a more specific title or update the existing
|
||||
page instead".
|
||||
3. **Pull upstream context.** If updating, fetch the current body with
|
||||
`mcp__atlassian.confluence_get_page_content(pageId)` and diff against the
|
||||
draft. Flag any section that was renamed or deleted upstream and carried
|
||||
forward in the draft without intent.
|
||||
4. **Lint the body.** For each of the checks below, return a line number and
|
||||
a short rationale. See [references/checks.md](references/checks.md) for the
|
||||
full list and severity table.
|
||||
5. **Slop pass.** Run the `unslop` skill on the body. If unslop returns more
|
||||
than 5 fixes for a page under 100 lines, or more than 10 for any page,
|
||||
return **REVISE** — the author should reread, not the agent.
|
||||
6. **Diagram sanity.** For every `{plantuml}` block, parse to a `.puml` temp
|
||||
file and run `plantuml -checkonly -syntax` if `plantuml` is on `$PATH`. If
|
||||
the tool is missing, skip the parse and warn — do not block on a missing
|
||||
optional tool.
|
||||
7. **Render verdict.**
|
||||
|
||||
## Verdict shape
|
||||
|
||||
```
|
||||
PASS:
|
||||
- ready to post; no blocking issues
|
||||
- (optional) minor notes for the author
|
||||
|
||||
REVISE:
|
||||
- L<line>: <rule> — <one-line fix>
|
||||
- L<line>: <rule> — <one-line fix>
|
||||
- ...
|
||||
- estimated fix effort: <s|m|l>
|
||||
|
||||
BLOCK:
|
||||
- <rule>: <what's wrong, what to do instead>
|
||||
- <rule>: ...
|
||||
```
|
||||
|
||||
The verdict is the only thing the calling skill should consume. Everything
|
||||
else (diff, lint output, slop report) goes to stderr / a side file for the
|
||||
human.
|
||||
|
||||
## What the reviewer does NOT do
|
||||
|
||||
- **Edit the draft.** The author or the `confluence-page` skill applies fixes.
|
||||
Reviewer that also edits is hard to audit.
|
||||
- **Post anything.** The reviewer never calls a write MCP tool.
|
||||
- **Judge voice.** Use `unslop` for that. The reviewer enforces structure,
|
||||
safety, and rendering correctness; unslop enforces voice.
|
||||
- **Approve secrets in test data.** Even "obvious" test fixtures get blocked.
|
||||
If you need sample data with realistic-looking identifiers, generate them
|
||||
with the project's standard placeholder vocabulary.
|
||||
|
||||
## Severity table
|
||||
|
||||
| Severity | Returns | Examples |
|
||||
|----------|---------|----------|
|
||||
| Blocker | BLOCK | secret leak, wrong parent, wrong space, title collision, raw wiki markup in storage body |
|
||||
| Major | REVISE | unrendered macro, broken internal link, image without alt text, slop cluster |
|
||||
| Minor | PASS (with note) | inconsistent heading levels, missing one-line summary, sub-optimal anchor text |
|
||||
|
||||
Full rule list: [references/checks.md](references/checks.md).
|
||||
|
||||
## Related
|
||||
|
||||
| Skill | Role |
|
||||
|-------|------|
|
||||
| `confluence-page` | Calls the reviewer before every create/update |
|
||||
| `unslop` | Voice-level pass; the reviewer delegates voice to it |
|
||||
| `diagram-plantuml` | Owns PlantUML syntax; the reviewer delegates diagram parsing to it |
|
||||
@@ -0,0 +1,77 @@
|
||||
# Page Reviewer — Checks
|
||||
|
||||
The full rule list the `page-reviewer` skill runs. Each check has a severity
|
||||
(BLOCKER / MAJOR / MINOR), the pattern it looks for, and the verdict it
|
||||
returns.
|
||||
|
||||
## BLOCKER
|
||||
|
||||
| ID | Rule | How to detect |
|
||||
|----|------|---------------|
|
||||
| `B-SECRET` | Body contains a token, key, password, or PII pattern from `confluence-page/references/secrets.md` | `grep -nE "<patterns>" <draft>` |
|
||||
| `B-MIRROR-PATH` | Body references a local mirror path (`~/Netcracker/Projects/NDO/knowledge/...`) | grep for the root path |
|
||||
| `B-COLLISION` | A page with the same title exists under the same parent | `confluence_search` for the title |
|
||||
| `B-WRONG-SPACE` | Draft targets a space that doesn't match content kind (see `confluence-page/references/space-keys.md`) | manual check by reviewer |
|
||||
| `B-WRONG-FORMAT` | Body is wiki markup or Markdown, not storage XHTML | header doesn't start with `<p`, `<h`, `<ac:`, or `<table`; presence of `---` front-matter fences |
|
||||
| `B-LOCAL-FS-LINK` | Body contains `file://`, `~/`, or `/home/masi1023/` paths | grep |
|
||||
| `B-CUSTOMER-PII` | Customer name, hostname, or payment info in body | grep + manual review |
|
||||
| `B-PARENT-LOOP` | Parent resolves to a descendant of itself | `confluence_get_page` ancestry walk |
|
||||
|
||||
## MAJOR
|
||||
|
||||
| ID | Rule | How to detect |
|
||||
|----|------|---------------|
|
||||
| `M-UNRENDERED-MACRO` | `{plantuml}`, `{code}`, `{info}`, `{note}`, etc. not in proper storage form | grep for unclosed or naked `{...}` macros |
|
||||
| `M-BROKEN-LINK` | Internal link points to a page id that doesn't exist or a URL that 404s | `confluence_search` for the target title; HEAD on the URL |
|
||||
| `M-MISSING-ALT` | Image element without `ac:alt` | grep for `<ac:image` without `ac:alt` |
|
||||
| `M-DIAGRAM-IN-PANEL` | PlantUML block inside an info / note / warning panel | grep + structure check |
|
||||
| `M-DIAGRAM-IN-CODE` | PlantUML block inside a `{code}` block | grep + structure check |
|
||||
| `M-CODE-NO-LANG` | `{code}` block without `language` parameter | grep + structure check |
|
||||
| `M-EMPTY-SECTION` | Section heading followed by nothing or a single sentence | structure walk |
|
||||
| `M-STALE-SECTION` | Section in draft was deleted from upstream since the last pull (update flow) | diff against `confluence_get_page_content` |
|
||||
| `M-SLOP-CLUSTER` | `unslop` skill returns >5 fixes for a 30-line block | unslop report count |
|
||||
| `M-NO-SUMMARY` | First paragraph is missing for a how-to or runbook | structure check |
|
||||
| `M-OVER-300` | Page body is over 300 lines and no justification header exists | `wc -l` |
|
||||
|
||||
## MINOR (PASS with note)
|
||||
|
||||
| ID | Rule | How to detect |
|
||||
|----|------|---------------|
|
||||
| `m-HEADING-LEVEL` | Skipped heading level (h1 → h3 with no h2) | structure walk |
|
||||
| `m-MISSING-ANCHOR` | Cross-page reference without an explicit anchor text | structure walk |
|
||||
| `m-LOOSE-LINK` | "click here", "this link" | grep |
|
||||
| `m-EMOJI-IN-HEADING` | Emoji in headings that (h1 / h2) | grep |
|
||||
| `m-CAPITALIZED-LINE` | Long uppercase run (more than 5 words) | grep |
|
||||
| `m-MULTI-COLON` | Multiple consecutive `:` in a sentence | grep |
|
||||
| `m-RUN-ON-LINE` | A single line over 200 chars | `awk '{ print length, NR }'` |
|
||||
|
||||
## Severity → verdict
|
||||
|
||||
```
|
||||
BLOCKER > 0 → BLOCK
|
||||
MAJOR > 0 → REVISE
|
||||
MINOR > 0 → PASS (with note)
|
||||
```
|
||||
|
||||
A single BLOCKER short-circuits. The reviewer still lists MAJOR / MINOR
|
||||
findings so the author can fix them in the same pass.
|
||||
|
||||
## Diff mode (updates)
|
||||
|
||||
When the reviewer is called for an update, also run:
|
||||
|
||||
| ID | Rule |
|
||||
|----|------|
|
||||
| `D-UNINTENDED-DROP` | A section in the upstream body that the draft does not have (and was not intentionally removed by `versionMessage`) |
|
||||
| `D-UNINTENDED-RENAME` | A heading in the upstream body that the draft has under a different name |
|
||||
| `D-STALE-VERSION` | The `versionMessage` does not match the change set |
|
||||
|
||||
`D-` rules are MAJOR by default; BLOCKER only if the dropped content was
|
||||
flagged as load-bearing by the previous reviewer.
|
||||
|
||||
## What the reviewer does NOT check
|
||||
|
||||
- Correctness of the technical content — that's an SME responsibility
|
||||
- Style / voice — that's `unslop`
|
||||
- Compliance with team conventions outside this list — escalate to the page
|
||||
owner
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
name: unslop
|
||||
description: Strip AI phrasing from prose before it is posted to a Confluence page, sent to a customer, or shared in chat. Use when a draft sounds like it was written by an LLM: ornamental hedging, breathless transitions, vague intensifiers, symmetrical bullet padding, or any of the other tells listed in references/tells.md.
|
||||
---
|
||||
|
||||
# Unslop
|
||||
|
||||
The page-reviewer catches structural problems; this skill catches voice
|
||||
problems. Both run before a page goes live.
|
||||
|
||||
The unslop pass is line-anchored, deterministic, and reversible. It returns a
|
||||
diff-style report; the author or the calling skill applies the changes.
|
||||
|
||||
## Hard rules
|
||||
|
||||
- **Never edit silently.** Every change appears in the report with the line,
|
||||
the original phrase, and the suggested replacement.
|
||||
- **Never invent voice.** The rewrite defaults to short, declarative, and
|
||||
Netcracker-house — see [references/house-style.md](references/house-style.md).
|
||||
- **Don't rewrite technical content.** If a sentence is slop but the
|
||||
technical claim is correct, fix the phrasing, not the claim.
|
||||
- **Don't rewrite quotes.** Code, command output, error messages, and
|
||||
customer-quoted text stay literal.
|
||||
- **Don't touch structured data.** Tables, lists of identifiers, file paths,
|
||||
URLs, and version numbers are not slop.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Read the draft. Mark each line with one of: `clean`, `slop`, `unsure`.
|
||||
2. For each `slop` line, look up the tell in
|
||||
[references/tells.md](references/tells.md) and propose a concrete rewrite.
|
||||
3. For each `unsure` line, leave it alone and flag it for the author with a
|
||||
short rationale.
|
||||
4. Cluster check. If more than 5 slop lines appear in a 30-line block, mark
|
||||
the block `rewrite-block` — voice problems cluster, and the author should
|
||||
rewrite that section by hand rather than accept a chain of small fixes.
|
||||
5. Return the report.
|
||||
|
||||
## Report shape
|
||||
|
||||
```
|
||||
# Unslop report — <page slug>
|
||||
|
||||
L<line>: <tell> — <phrase>
|
||||
> <original>
|
||||
+ <proposed rewrite>
|
||||
L<line>: <tell> — <phrase>
|
||||
> <original>
|
||||
+ <proposed rewrite>
|
||||
|
||||
# Rewrite-block sections (cluster of >5 slop lines)
|
||||
- L<start>-L<end>: <section title>
|
||||
|
||||
# Uncertain — author decides
|
||||
- L<line>: <short rationale>
|
||||
```
|
||||
|
||||
The calling skill applies line-by-line fixes; the author rewrites the marked
|
||||
sections.
|
||||
|
||||
## What counts as slop
|
||||
|
||||
Full list with examples in [references/tells.md](references/tells.md). The
|
||||
high-frequency ones:
|
||||
|
||||
| Tell | Example | Fix |
|
||||
|------|---------|-----|
|
||||
| Ornamental hedging | "It's important to note that…" | Delete the preamble. |
|
||||
| Breathless transition | "Let's dive in!" | Replace with the next fact. |
|
||||
| Vague intensifier | "really", "very", "quite" (when not load-bearing) | Delete. |
|
||||
| Symmetric padding | "X is Y. X is also Z. Both X's are…" | Pick the one that matters. |
|
||||
| AI résumé | "With over X years of experience…" | Replace with the actual fact. |
|
||||
| Performative caveat | "It's worth mentioning that…" | Delete or move to the conclusion. |
|
||||
| Marketing tone | "seamlessly", "robust", "powerful", "leverage" | Replace with the specific capability. |
|
||||
| Triplet | "fast, reliable, and scalable" | Pick the one that is actually true, drop the rest. |
|
||||
| Heading question | "Why is X important?" | State the answer, not the question. |
|
||||
| Sign-off | "Hope this helps!", "Let me know if you have questions!" | Delete. |
|
||||
|
||||
## When to refuse
|
||||
|
||||
- The text is a customer-quoted block, a log line, or a code comment — leave
|
||||
it alone.
|
||||
- The text is technical and correct; only the framing is fluffy. Fix the
|
||||
framing, not the substance.
|
||||
- The rewrite would change the meaning. Mark it `unsure` and let the author
|
||||
decide.
|
||||
|
||||
## Related
|
||||
|
||||
| Skill | Role |
|
||||
|-------|------|
|
||||
| `page-reviewer` | Calls unslop as part of the pre-post gate |
|
||||
| `confluence-page` | Uses the report to apply line-by-line fixes |
|
||||
|
||||
## Limitations
|
||||
|
||||
Unslop is a heuristic pass, not a guarantee. A page can be technically
|
||||
slop-free and still sound corporate, and a page that sounds conversational
|
||||
can still be slop-free. Voice is not the only quality dimension; this skill
|
||||
addresses one of them.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Netcracker House Style
|
||||
|
||||
The voice and shape unslop rewrites toward when nothing else is specified.
|
||||
This is the default, not a mandate — pages with a stated owner voice
|
||||
override this list.
|
||||
|
||||
## Sentence
|
||||
|
||||
- Active voice by default.
|
||||
- One idea per sentence. Two if they're tightly coupled.
|
||||
- Sentence length mostly 8–25 words. Long sentences only when the structure
|
||||
is parallel.
|
||||
- No run-on lines (>200 chars) in body paragraphs. Code and tables exempt.
|
||||
|
||||
## Paragraph
|
||||
|
||||
- First sentence carries the claim.
|
||||
- Body sentences support it.
|
||||
- Last sentence ties it to the next paragraph or to a link.
|
||||
- 3–6 sentences for most paragraphs. Lists break up long paragraphs; they do
|
||||
not replace them.
|
||||
|
||||
## Headings
|
||||
|
||||
- Verb-first when possible: "Run the migration" not "Migration".
|
||||
- Question headings only when the body answers the question in the first
|
||||
sentence.
|
||||
- No emoji in h1 / h2. Emoji ok in h3 and below when it's a stable convention.
|
||||
|
||||
## Lists
|
||||
|
||||
- Parallel grammatical form across items.
|
||||
- One concept per item. Two ideas → two items.
|
||||
- Bullet list for unordered; numbered list for steps.
|
||||
|
||||
## Tables
|
||||
|
||||
- Column headers in `Title case`.
|
||||
- Numbers right-aligned in monospace columns; labels left-aligned in prose.
|
||||
- Empty cells get `<empty>` or are filled — never blank.
|
||||
|
||||
## Code
|
||||
|
||||
- Inline code for file names, env vars, commands, identifiers.
|
||||
- Fenced blocks with language tag for anything longer than one line.
|
||||
- Comments inside code blocks explain *why*, not *what*.
|
||||
|
||||
## Links
|
||||
|
||||
- Anchor text describes the destination. "click here" is a smell.
|
||||
- External links open in same tab; the Confluence renderer adds the
|
||||
indicator.
|
||||
- Internal page links by title, not by URL — rename the page and the link
|
||||
follows.
|
||||
|
||||
## Voice
|
||||
|
||||
- First person plural ("we") when the team owns the page.
|
||||
- Third person when describing a component or a product.
|
||||
- Avoid "I" on team-owned pages.
|
||||
- Avoid the passive voice when it hides who did the thing.
|
||||
|
||||
## What unslop does not change
|
||||
|
||||
- Code blocks, command output, error messages, log lines.
|
||||
- Customer quotes (marked as such).
|
||||
- Commit messages, ticket numbers, identifiers.
|
||||
- Acronyms the audience uses.
|
||||
|
||||
## Calibration
|
||||
|
||||
A page rewritten by unslop should pass the "would a senior engineer send
|
||||
this to their team?" test. If yes, ship. If the page still reads corporate,
|
||||
escalate to the owner — unslop is not the right tool for that.
|
||||
@@ -0,0 +1,75 @@
|
||||
# Slop Tells
|
||||
|
||||
A worked catalogue of the phrases that mark prose as AI-generated. The
|
||||
`unslop` skill greps the draft for each row and reports a fix.
|
||||
|
||||
The list is heuristic. A page can match several tells and still read well;
|
||||
a page can match none and still feel corporate. Use this as a checklist, not a
|
||||
verdict.
|
||||
|
||||
## High-frequency tells
|
||||
|
||||
| Tell | Example | Default fix |
|
||||
|------|---------|-------------|
|
||||
| Ornamental hedging | "It's important to note that…" | Delete the preamble |
|
||||
| Breathless transition | "Let's dive in!", "Now, let's explore…" | Replace with the next fact |
|
||||
| Vague intensifier | "really", "very", "quite", "rather" (when not load-bearing) | Delete |
|
||||
| Symmetric padding | "X is Y. X is also Z. Both X's are…" | Pick the one that matters |
|
||||
| AI résumé | "With over X years of experience…" | Replace with the actual fact |
|
||||
| Performative caveat | "It's worth mentioning that…" | Delete or move to the conclusion |
|
||||
| Marketing tone | "seamlessly", "robust", "powerful", "leverage", "cutting-edge" | Replace with the specific capability |
|
||||
| Triplet | "fast, reliable, and scalable" | Pick the one that is actually true |
|
||||
| Heading question | "Why is X important?" | State the answer, not the question |
|
||||
| Sign-off | "Hope this helps!", "Let me know if you have questions!" | Delete |
|
||||
| Throat-clearing | "In this article, we will…" | Delete the article and start with the subject |
|
||||
| Mirror transition | "As we have seen…" | Replace with the actual finding |
|
||||
| Manufactured urgency | "In today's fast-paced world…" | Delete |
|
||||
| Generic closer | "To learn more, contact…" | Replace with the actual link or contact |
|
||||
|
||||
## Mid-frequency
|
||||
|
||||
| Tell | Example | Default fix |
|
||||
|------|---------|-------------|
|
||||
| Bureaucratic noun | "perform a verification of" | "verify" |
|
||||
| Nominalised verb | "the implementation of the feature" | "implementing the feature" |
|
||||
| Possessive hedge | "in our experience" | Drop unless backed by data |
|
||||
| Padded qualifier | "essentially", "basically", "fundamentally", "literally" | Delete |
|
||||
| Redundant pair | "each and every", "first and foremost", "any and all" | Pick one |
|
||||
| Process name as action | "we will be performing a build" | "we will build" |
|
||||
| Apology | "Apologies for the inconvenience" | Replace with the fix |
|
||||
| Hyperbole | "game-changer", "revolutionary", "paradigm shift" | Replace with the actual claim |
|
||||
| Cult of positivity | "We are excited to announce…" | Replace with the news |
|
||||
| Generic advice | "Best practices include…" | Replace with the specific practice |
|
||||
|
||||
## Low-frequency (still flag)
|
||||
|
||||
| Tell | Example | Default fix |
|
||||
|------|---------|-------------|
|
||||
| Anachronism | "in the year 2026" | Drop the year unless it disambiguates |
|
||||
| Self-reference | "this article", "this section", "as stated above" | Replace with the thing |
|
||||
| Passive that hides the actor | "It was decided that…" | "We decided…" |
|
||||
| Telegraphic metaphor | "drowning in data", "needle in a haystack" | Replace with the literal state |
|
||||
| Fake precision | "in 90% of cases" | Replace with the source |
|
||||
|
||||
## What is NOT slop
|
||||
|
||||
- Technical jargon used precisely (`asynchronous`, `idempotent`,
|
||||
`backpressure`).
|
||||
- Repetition for emphasis that the reader actually needs.
|
||||
- Headings that match a list of canonical section titles (`Overview`,
|
||||
`Steps`, `Verification`).
|
||||
- Code, command output, error messages, customer-quoted text.
|
||||
- Acronyms and abbreviations the audience knows.
|
||||
|
||||
## Cluster detection
|
||||
|
||||
Slop tends to cluster. A single slop line in 30 is a minor fix. Five slop
|
||||
lines in 10 means the author wrote the paragraph by stream-of-prompting; the
|
||||
whole section should be rewritten by hand. The `unslop` skill flags cluster
|
||||
sections as `rewrite-block` rather than proposing per-line fixes.
|
||||
|
||||
## When to escalate
|
||||
|
||||
A draft that reads well but uses a non-AAVE corporate voice should not be
|
||||
unslopped into something else; flag it for the author. The skill rewrites
|
||||
*slop*, not *voice*.
|
||||
Reference in New Issue
Block a user