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/`.
|
||||
Reference in New Issue
Block a user