[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71T07E59WEJTP97S4P8AMKK":3,"skill-same:01M71T07E59WEJTP97S4P8AMKK":70},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":37,"linkOnly":38,"markdownContent":39,"markdownBody":40,"frontMatter":41,"refName":48,"commitSha":49,"skillDirectory":50,"forksCount":51,"repositoryHtmlUrl":52,"repositoryHomepageUrl":6,"ownerHtmlUrl":53,"ownerBlogUrl":54,"ownerDescription":55,"updatedAt":56,"install":57,"resources":69},"01M71T07E59WEJTP97S4P8AMKK","publish",null,"Use when a finished markdown document — plan, audit or review findings, retro, decision, or knowledge page — needs to reach its destination: the shared-docs vault, the repo's documentation\u002F tree, a GitHub issue, a PR description, the chat session, a Notion page, or the default private session artifact area. The single output sink: skills author content, publish delivers it. For a quick vault note rather than a finished document, use \u002Fclaudna:claudron.","Claudfather\u002FclauDNA","Claudfather","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F281278891?v=4","01M71SX82K0TBGQ394AB2G1T5Z","01M71SX83CE1S8YC06K9P3P962",0,"Apache-2.0","https:\u002F\u002Fgithub.com\u002FClaudfather\u002FclauDNA\u002Fblob\u002Fmain\u002Fskills\u002Fpublish\u002FSKILL.md",[],[5,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36],"needs","destination","update","run","audit","markdown","plan","documentation","dry","review","author content","URL","when","knowledge","decision","review findings","notion","quick","shared","2026-11-10 13:02:02",false,"---\nname: publish\nuser-invocable: true\ndescription: \"Use when a finished markdown document — plan, audit or review findings, retro, decision, or knowledge page — needs to reach its destination: the shared-docs vault, the repo's documentation\u002F tree, a GitHub issue, a PR description, the chat session, a Notion page, or the default private session artifact area. The single output sink: skills author content, publish delivers it. For a quick vault note rather than a finished document, use \u002Fclaudna:claudron.\"\nargument-hint: \"\u003Csource-file-or-dir> [--to artifacts|vault|docs|github-issue|github-pr|session|notion] [--dir \u003Cpath>] [--update \u003Cissue#|url>] [--repo \u003Cname>] [--dry-run]\"\nrequires:\n  - cli: claudron\n    reason: \"Optional — `--to vault` routes the doc through `claudron capture` when the engine is present; without it, that one adapter degrades per the standard notice in ..\u002F_shared\u002Fclaudron-engine.md §3.1 and writes the frozen raw tree. Every other adapter is unaffected\"\n---\n\n# Publish\n\n> **Codex:** Read `..\u002F_shared\u002Fcodex-tools.md` before following this skill. Apply its tool, root and dispatch mappings throughout.\n\nMarkdown-first, output-last. Takes a doc with frontmatter and publishes it to the right destination. The doc is always the source of truth — \u002Fclaudna:publish is just the adapter.\n\nThe default destination is the current native session's private `artifacts` area. Other destinations are explicit exports; native receipts and consumer acceptance remain merge\u002Frelease gates. Resolve the loaded package root through [`..\u002F_shared\u002Fclaudna-root.md`](..\u002F_shared\u002Fclaudna-root.md); examples use the actual `python3 -B \u003Cclaudna-root>\u002Flib\u002Fclaudna\u002Fsession_store` entrypoint.\n\n**This skill is the single output sink.** Analysis\u002Fplanning skills are *authors*: they produce a markdown doc with valid frontmatter and the house-style body skeleton, then hand it to \u002Fclaudna:publish. \u002Fclaudna:publish is the *publisher*: it enforces house style, dedups per-medium, and routes the one manuscript to whichever edition the caller asked for. Skills must never call `gh issue create` \u002F `gh pr create` themselves — they delegate here. The canonical house-style spec (frontmatter schema, per-type body skeleton, label taxonomy) lives in `..\u002F_shared\u002Foutput-guide.md`; this skill enforces it.\n\n## Arguments\n\nParse `$ARGUMENTS` at invocation:\n- **First positional arg:** Path to the source markdown file — or, for artifacts\u002Fdocs family mode, a directory holding one `00_*.md` master plus `NN_*.md` phase docs. Required except for `--to session`, which may receive the document directly in context without a file.\n- `--to \u003Cdest>`: Destination adapter. One of: `artifacts` (default), `vault`, `docs`, `github-issue`, `github-pr`, `session`, or `notion`.\n- `--dir \u003Cpath>`: docs adapter only — the target directory under `documentation\u002F` (the calling skill knows its category; registry in `..\u002F_shared\u002Fdocumentation-standard.md` §2). Required with `--to docs`.\n- `--update \u003Cissue#|url>`: Replace the named GitHub issue's body instead of creating anything. Implies `--to github-issue` — the only adapter with an update path — so `--to` may be omitted. See \"In-place update\" under the github-issue adapter.\n- `--repo \u003Cname>`: Target repository (for github adapters).\n- `--dry-run`: Show what would be published without doing it.\n\n---\n\n## Step 1: Read and Validate Source (house style)\n\nFor an in-context `session` document, validate its supplied content below without allocating files. **Before reading any source content**, resolve each explicitly selected source file or asset path (including symlink aliases) and determine whether it is a canonical artifact under the effective root. If it is, validate that exact absolute path and owner with the existing `continuity artifact-path` explicit-path form shown under the artifacts adapter below. Apply this gate to every canonical source for every destination adapter, including files individually selected from a family; never blanket-read a directory or read a canonical payload before its path is authorized. Validate current-session and other-session canonical paths. A current-owner private\u002Fmanual artifact is permitted; another owner's source requires a public, bounded scope. Missing, private, denied, stale, or otherwise uncertain validation means stop before content read, preserve the source, and report partial\u002Funavailable. Noncanonical scratch\u002Fuser sources follow the existing Step 1 reads and validation below.\n\nAfter the gate, read the allowed source markdown file. Parse YAML frontmatter. Validation is **deep** — a malformed manuscript is never published. If any check below fails, report the specific errors and stop. (Directory source: this step runs per doc via the artifacts\u002Fdocs family loop.)\n\n### 1a. Frontmatter schema\n\nValidate required fields exist and are well-formed:\n\n| Field | Rule |\n|-------|------|\n| `title` | non-empty string |\n| `type` | a valid note type — vocabulary table in `..\u002F_shared\u002Foutput-guide.md` §3 (the repo's only enum table, rendered from the Claudron SSOT) |\n| `status` | valid for the `type` per the §3 vocabulary table: canonical values pass silently; accepted legacy values (e.g. `active` on a knowledge doc) pass with a one-line mapping note — never a rejection |\n| `owner` | non-empty string |\n| `created` | valid `YYYY-MM-DD` |\n\nOptional fields: `tags` (→ issue labels), `repos` (→ vault dir + repo inference), `links` (publish writes the destination URL back here for editable noncanonical sources), `updated`, `expires`, `description`.\n\n**Canonical artifact source rule:** once a file is a canonical artifact, its content and frontmatter remain unchanged during later exports. In particular, do not add an issue, Notion, or other destination URL to that canonical source. For an actual returned non-chat outcome, record the destination in a private receipt under the current session's artifact area; this applies to every destination adapter and never copies the canonical source. A failed or uncertain destination may be recorded only with its actual failed\u002Funknown status, never as success. Session\u002Fchat output and dry-run remain mutation-free and create no receipt. A scratch export edition derived from a canonical source retains that source's ownership\u002Fprivacy gate and receipt obligation: record the canonical source hash plus the rendered edition hash and formatting\u002Fcross-link changes. Copying into scratch never bypasses canonical protection. Existing write-back behavior remains available for independently authored noncanonical user sources where the adapter below specifies it.\n\nPass-through fields (accepted, never rejected, never required — output-guide §3): `maturity`, `schema_version`, and any `x-*`-prefixed field. Publish carries them through untouched and never validates their values.\n\n### 1b. Body skeleton (per `type:`)\n\nThe body must match the house-style skeleton for its `type:`. This is keyed off `type:` (≤6 types) — publish validates the *skeleton*, never the prose, and never rewrites the body.\n\n- **`audit`, `review`, `plan`** — must contain the implementation-ready skeleton (see `..\u002F_shared\u002Foutput-guide.md` Section 4.1):\n  `## Summary`, `## Evidence`, `## Implementation Plan` (with `### Dependencies`, `### Blocks`, `### Steps`), `## Test Plan`, `## Verification Checklist`, `## What NOT To Do`, `## Context`.\n  **Hard gate:** the `## Implementation Plan` heading and its `### Steps` subsection MUST be present. This is the contract `\u002Fclaudna:build --source github` depends on to tell an implementable issue from a findings-only one — without it, `--auto` implementation blocks. Reject the publish if missing.\n- **`decision`, `knowledge`, `runbook`** — require a non-trivial body (not just frontmatter) and a leading `#`\u002F`##` heading. No fixed section gate (see `..\u002F_shared\u002Fdocumentation-standard.md`); validate presence, not structure.\n\n**Master-doc exception (artifacts and docs adapters):** a `00_*.md` doc validates like the knowledge tier — frontmatter + non-trivial body + leading heading, no §4.1 skeleton gate — even when its `type:` is `audit`\u002F`review`\u002F`plan`, whether it arrives as a family member (directory source) or alone (single-doc source: retros, dashboards, findings reports). Masters and standalone reports are inventories, not implementation plans; the skeleton hard gate exists for build readiness, which is a property of the `NN_*` phase docs (which validate in full). This exemption is the design, not a workaround.\n\n---\n\n## Step 2: Route to Adapter\n\nThe disk-backed adapters serve distinct planes — the plane doctrine and which-door table live in `..\u002F_shared\u002Fdocumentation-standard.md`:\n\n- **`vault`** → the shared-docs vault (cross-project referential knowledge; INDEX-discovered)\n- **`docs`** → the current repo's `documentation\u002F` tree (work-in-flight + repo-coupled records; git\u002FPR-discovered)\n- **`artifacts`** → generated finished output in the current native session's private artifact area; the default\n\n### Adapter: artifacts (default)\n\nUse this adapter when no destination is specified or the caller selects `--to artifacts` (workflow `--output artifacts`). It stores selected finished output in the current session's private artifact area. It does not publish a global pointer or make artifacts broadly discoverable.\n\n**Identity and allocation.** Obtain the current session ID and host from the qualified native runtime source. Never infer identity from cwd, time, an operation ID, a filename, or a guessed value. Resolve the loaded plugin root via `..\u002F_shared\u002Fclaudna-root.md`, then call the existing CLI:\n\n```bash\npython3 -B \"\u003Cclaudna-root>\u002Flib\u002Fclaudna\u002Fsession_store\" scratch \\\n  --session \"\u003Cverified-native-sid>\" --host \"\u003Cprovider>\" --label \"publish-artifacts\"\npython3 -B \"\u003Cclaudna-root>\u002Flib\u002Fclaudna\u002Fsession_store\" paths \\\n  --session \"\u003Cverified-native-sid>\" --host \"\u003Cprovider>\" --kind artifacts --create\n```\n\nAllocate scratch only when promotion or working files need it; reuse a caller's scratch with cleanup left to that owner. Use only the exact returned scratch and artifact paths. `scratch` allocates private temporary work; `paths --kind artifacts --create` resolves\u002Fcreates the private durable area. A missing, conflicting, or unverified identity, or an ordinary permission failure, makes this route partial\u002Funavailable: stop the artifact write and report the reason. Do not fall back to an OS temp path or claim the host is unsupported. A dry run does neither allocation nor writes. The `session` adapter remains chat-only and does not persist files.\n\n**Input and validation.** Accept a single finished markdown file or a family with exactly one `00_*.md` master and one or more `NN_*.md` phases. Preserve Step 1 validation, including the master-doc presence-only exception, and the docs adapter's all-or-nothing family validation. Non-markdown assets may be included only when explicitly selected as finished output. Never copy the surrounding scratch tree, credentials, or unrelated private files.\n\nIf the selected input is already a canonical artifact, validate its exact known path before reading its content, whether it belongs to the current session or another session. Pass the current session\u002Fhost, an explicit scope, the source session ID, and that absolute path to the existing CLI; the explicit-path form does not use `--workflow`:\n\n```bash\npython3 -B \"\u003Cclaudna-root>\u002Flib\u002Fclaudna\u002Fsession_store\" continuity artifact-path \\\n  --session \"\u003Ccurrent-sid>\" --host \"\u003Cprovider>\" --scope \"\u003Cscope>\" \\\n  --from-session \"\u003Csource-sid>\" --path \"\u003Cabsolute-source-path>\" --json\n```\n\nProceed only if the result validates that same path and ownership. A current-owner private\u002Fmanual artifact is permitted. Another owner's artifact requires a public, bounded scope. Missing, private, denied, or unverifiable ownership is denied before content read. This validation is for the explicitly selected path; it does not require or mutate a global pointer. For a same-session source, use its exact canonical path and do not create a replacement merely to republish it. Apply the same gate to canonical inputs routed to vault, docs, GitHub, Notion, or any other adapter. Do not copy a canonical source into a new artifact location merely to export it; store only the current-owner private publication receipt described above.\n\n**Promotion of scratch output.** Leave a selected source that is already canonical in place. For a new output, promote only the validated selected file\u002Ffamily and explicitly selected finished assets. Do not overwrite an existing canonical target: if it already contains identical bytes, report it as already canonical; if content differs, stop and surface the conflict. Stage within the private artifact directory on the same filesystem, retain ordinary private permissions (directories `0700`, files `0600`), hash each source, copy to staging, verify hashes, then atomically install into an absent canonical destination without replacement and verify final hashes. A concurrent destination collision is a conflict: retain staging and the existing canonical bytes. A pre-check followed by an overwriting rename is insufficient. Remove the exact allocated scratch only after all writer children have actually exited and verification succeeds. On failure or an uncertain writer, preserve scratch and report partial; never clean by glob or age.\n\n**Canonical export receipts.** For an actual (non-dry-run) invocation of any adapter other than `session`, preserve each canonical source and send only the explicitly selected finished docs\u002Fassets through the selected adapter. Before reading, publishing, or exporting the canonical source, resolve the current session's private receipt destination with `paths --kind artifacts --create` using the verified current SID\u002Fhost; if that identity or ordinary permission check fails, stop before destination mutation and report partial\u002Funavailable. After an actual returned result, write a private receipt owned by the current session under that artifact area, recording each source path and content hash, destination, and actual returned result (URL\u002Fpath\u002Fstatus). Use a unique receipt file with ordinary private permissions; do not create a shared ledger. If receipt storage fails after an external result, preserve the source and report that the result occurred but receipt persistence failed; do not claim the receipt exists. Do not write a receipt during dry-run, session\u002Fchat output, or for a result that did not occur. A genuine failed\u002Funcertain destination may be recorded only with its actual failed\u002Funknown status. The github-pr adapter formats a body only, so its returned result is formatting output unless the caller separately creates a PR and returns its URL.\n\nNative host receipts and consumer acceptance remain pending before merge\u002Frelease. This source contract is draft implementation, not native acceptance. Preserve that distinction in qualification receipts.\n\n### Adapter: vault (explicit export)\n\nThis plane has two backends — a Claudron vault (engine) and a raw tree (fallback). Run the **detection ladder in `..\u002F_shared\u002Fclaudron-engine.md` §1** first, then route:\n\n**Engine path — verdict present-with-vault.** Route the finished doc through Claudron rather than writing files directly; map its frontmatter onto a capture call:\n\n```bash\n# provenance (flags-capable engine only — see below): source_url and source_type ride in the finding file\nclaudron capture --stdin --json \u003C \u003Cfinding-file>\n```\n\nWrite the finding as JSON to `\u003Cfinding-file>`, a file in `\u003Cscratch>` (`..\u002F_shared\u002Forchestration-guide.md` §1), with the Write tool first (`type`, `title`, `body`, `tags`, `project`; `\u002Fclaudna:capture` Step 4): the title and body never go on the command line. `project` comes from the doc's `repos:` \u002F `--repo` (omit if unscoped). Validate the envelope (claudron-engine.md §2) and branch on `data.action`: `created` → report `data.path`; `suggest_update` \u002F `suggest_supersede` → surface `data.reason` and the existing note to the caller (the engine's index-backed dedup replaces the raw adapter's file-compare); `rejected` (exit 1) → surface the validation errors. An engine failure *during* capture (exit 3 or an unrecognized envelope) degrades to the fallback path below, per claudron-engine.md §3 — say so. Do **not** run `\u002Fclaudna:index` — the vault is engine-indexed (documentation-standard §10). Maturity is never set here; the engine stamps `draft`.\n\n**Provenance (capability-probed).** If the doc's frontmatter carries `source_url` \u002F `source_type` (SCHEMA optional fields), put them in the finding file as `source_url` \u002F `source_type` — but **only on a flags-capable engine**: `data.engine_version` present and ≥ **0.4.0** (the Claudron C2 release that added the flags; the same version probe `\u002Fclaudna:capture` Step 1 uses, and the same floor its PreCompact defer keys on). An older \u002F absent \u002F unreadable version omits them (it would reject the flags, exit 2). Provenance is **never** folded into the body here: that trailing `Source:` workaround was capture's alone, and the github-pr adapter's `Source:` footer is an unrelated surface.\n\n**Fallback path — verdict present-no-vault or absent** (frozen behavior). Emit the standard degradation notice first (`..\u002F_shared\u002Fclaudron-engine.md` §3.1 — quote the `\u002Fclaudna:publish --to vault` row), then write the doc to the raw-tree directory for its `type:`:\n\n| Type | Destination |\n|------|-------------|\n| plan | `shared\u002Fplanning\u002Factive\u002F` (or `completed\u002F` for terminal statuses) |\n| decision | `shared\u002Fdecisions\u002F` |\n| knowledge | `shared\u002Fknowledge\u002F\u003Crepo>\u002F` (requires `repos:` field or `--repo` flag) |\n| runbook | `shared\u002Frunbooks\u002F` |\n| audit, review | `shared\u002Fplanning\u002Factive\u002F` |\n\nA memory-home type (`entity`, `concept`, `person`, `project`, `practice`) has no raw-tree destination: Claudron files homes itself (`memory-homes`), and this fallback is frozen. Stop and say the doc needs the engine; in `--auto`, the outcome is `blocked`, with installing Claudron as the unblock.\n\nIf the file already exists, compare and warn before overwriting (the raw adapter's dedup). After writing: (1) run `\u002Fclaudna:index` on the destination to update INDEX.md; (2) report the path. In `--auto`, the fallback sets `artifacts.engine: \"fallback\"` and puts the §3.1 notice verbatim in `errors[]` (claudron-engine.md §3) — the degradation is never inferred from `artifacts.engine` alone.\n\n**Plane-fit advisory** (either path): a `plan`\u002F`audit`\u002F`review` doc landing vault-ward gets a one-line note — \"unusual plane for this type: generated planning normally stays in private session artifacts; a repository edition is an explicit docs export\". Advisory only, never a block — fleet workflows legitimately share plans vault-side.\n\n### Adapter: docs\n\nWrite the doc — or doc family — into the current repo's `documentation\u002F` tree, the per-project plane. The author retains its canonical output in `\u003Cartifacts>` (`..\u002F_shared\u002Forchestration-guide.md` §1) and hands it here; publish is the single **placement path for finished docs** on this plane (status-marker write-backs and archiving by `\u002Fclaudna:build` are the documented exceptions).\n\n- `--dir \u003Cpath>` is **required** and must resolve under `documentation\u002F`. Reject anything outside it. Create the directory if it doesn't exist (the Write tool creates parents automatically) — don't fail on missing directories.\n- **Single-doc mode** (source is a file): validate per Step 1, write into `--dir`, report the path.\n- **Family mode** (source is a directory): the source holds **exactly one** `00_*.md` master + `NN_*.md` phase docs (the shape forge and the audit lenses produce); any other `.md` file fails the family (zero or multiple `00_*` files likewise); only explicitly selected finished non-markdown assets (screenshots, assets) copy through; never copy the surrounding directory or private working material. Loop per doc: phase docs validate against the full Step 1 contract including the §4.1 skeleton hard gate; the master validates under the master-doc exception (Step 1b). Validation reads are bounded — frontmatter (first ~15 lines) plus a Grep for the required section headings decide every check; never pull a family's full prose into context (the orchestration guide's context-window rules apply to the publishing orchestrator too). Any doc failing validation fails the whole family — report every error, write nothing (no partial families). On success, write all docs into `--dir` preserving filenames; report the directory and doc count.\n- **No INDEX step.** The docs plane is git\u002FPR-discovered — never run `\u002Fclaudna:index` here; INDEX.md is the vault plane's discovery layer.\n- **Dedup:** if a target file already exists, compare (bounded — same read rules as validation) and warn before overwriting (same rule as the vault adapter).\n- **Plane-fit advisory:** a `knowledge`\u002F`runbook` doc landing here gets a one-line note — \"unusual plane for this type: cross-project reference knowledge may belong in an explicitly selected vault edition\". Advisory only, never a block.\n\n### Adapter: github-issue\n\n**Dedup first (mandatory).** A dedup that silently misses is exactly the failure it exists to\nprevent, so this step is bounded on purpose and **states its bound in the output**. Run it\nbefore creating, then apply the decision rules in `..\u002F_shared\u002Foutput-guide.md` Section 4.5.\n\n**1. Pick 2–3 deliberately different terms** from the doc's title, tags and cited files. GitHub\nissue search is *lexical, not semantic* — it cannot match a duplicate whose filer chose different\nwords than you did. Rephrasing toward the symptom does not fix that, so vary the vocabulary\ninstead:\n\n| Term | Draw it from | Why |\n|---|---|---|\n| **Component** | a file, function, script or module name in the doc | strongest — file and symbol names are the one vocabulary two filers reliably share |\n| **Symptom** | what the reader observes going wrong | matches a duplicate filed from the outside in |\n| **Synonym** | the same defect said another way | the coverage the other two miss |\n\n**2. Run one query per term — separate commands, one term each.** Write each term to its own file in `\u003Cscratch>` with the Write tool first (`\u003Ccomponent-file>`, `\u003Csymptom-file>`, `\u003Csynonym-file>`); a term never goes into the command itself.\n\n```bash\ngh issue list --repo \u003Cowner>\u002F\u003Crepo> --search=\"$(cat \u003Ccomponent-file>)\" --state open --limit 20 --json number,title,url\ngh issue list --repo \u003Cowner>\u002F\u003Crepo> --search=\"$(cat \u003Csymptom-file>)\"   --state open --limit 20 --json number,title,url\ngh issue list --repo \u003Cowner>\u002F\u003Crepo> --search=\"$(cat \u003Csynonym-file>)\"   --state open --limit 20 --json number,title,url\n```\n\n**One term per query is the whole point of running three.** GitHub ANDs the words inside a\n`--search` string, so `--search \"dedup limit truncation\"` is a *single* search for issues\ncontaining all three words — it is not three searches, and it is **narrower than any one of\nthem alone**. Three terms in one query is the opposite of the coverage this step is asking for.\n\nRun each command unpiped and read its output. A `gh` call piped into anything reports the\n*pipe's* exit status, so a failed search becomes an empty result that passes every check below.\n\n**3. Check each count against the limit** before drawing any conclusion from it. The count must\nbe **strictly below the `--limit` you passed**.\n\n- **Count \u003C limit** → complete for that term. Its hits are the whole open match set, and a zero\n  is a real zero.\n- **Count == limit** → **truncated.** What it returned is still real — a duplicate you can see is\n  a duplicate, so act on it. What a truncated query cannot support is the **negative**: you\n  cannot tell \"no issue in this repo matches\" from \"none of the first 20 match\". Reporting *no\n  duplicate found* on the strength of a query that came back at the limit is a false negative,\n  not a clean result. Narrow the term (a filename or a symbol rather than a common word) or\n  raise `--limit`, re-run, and report both what you changed and the new count.\n\n**4. State the bound with the result** — every query verbatim, its count, the limit it ran under,\nand what was outside the search. \"No duplicate found\" is never the whole claim; \"no *open* match\nfor *these terms*\" is.\n\n```\nDedup: 3 queries against OPEN issues in \u003Cowner>\u002F\u003Crepo>, --limit 20 each.\n  \"\u003Ccomponent>\" → 2 hits (under limit)\n  \"\u003Csymptom>\"   → 0 hits (under limit)\n  \"\u003Csynonym>\"   → 7 hits (under limit)\n  Verdict: no open issue matched. Closed issues were not searched.\n```\n\nThen apply §4.5 to whatever the searches returned:\n\n- Exact match → prefer offering `--update` of the existing issue (§4.5); skip and report its URL only if the caller declines.\n- Related but different → create and add `Related: #NNN` to the body.\n- Same pattern, different location → prefer adding to an umbrella issue.\n\nThen create the issue:\n\n```bash\ngh issue create \\\n  --repo \u003Cowner>\u002F\u003Crepo> \\\n  --title \"$(cat \u003Ctitle-file>)\" \\\n  --body-file \u003Cbody-file> \\\n  --label \"$(cat \u003Clabels-file>)\"\n```\n\nWrite the title, the markdown body after the frontmatter, and the comma-separated labels to those three files, in `\u003Cscratch>`, with the Write tool first. Text in them never goes into the command itself.\n\nLabels come from `tags:` — skills express severity\u002Fpriority as tags (`priority:critical`, `security`, `auto-audit`, …); publish maps `tags` → `--label` and creates any missing labels. The `--repo` flag is required; if `repos:` is set in frontmatter with exactly one repo, infer from that.\n\nAfter creating:\n1. Add the issue URL to the source doc's `links:` frontmatter field only when the source is not a canonical artifact. For a canonical artifact, preserve it and record the URL in the current-owner private publication receipt.\n2. Report the issue URL.\n\n**In-place update (`--update \u003Cissue#|url>`).** When the caller names an existing issue — a re-forged plan body, an epic gaining its phase-issues table, a corrected audit — replace that issue's body instead of creating anything:\n\n```bash\ngh issue edit \u003Cnumber> --repo \u003Cowner>\u002F\u003Crepo> --body-file \u003Crendered-body-file>\n```\n\nRules: dedup is skipped (the target is explicit); the title is never changed (`gh issue edit --body-file` only — retitling stays a manual act); labels are additive only (`--add-label` for new `tags:`, never removing existing ones); report the issue URL and note \"updated in place\". The exact-match dedup rule lives in `..\u002F_shared\u002Foutput-guide.md` §4.5 and routes here: an exact match prefers an offered `--update` over a skip.\n\n### Adapter: github-pr\n\nFormat the doc as a PR description body. Write the formatted text to a file in `\u003Cscratch>` with the Write tool, for the caller to pass as `gh pr create --body-file \u003Cfile>`:\n\n```\n## Summary\n\n\u003Cfirst paragraph of doc body>\n\n## Details\n\n\u003Crest of doc body>\n\n---\nSource: \u003Csource file path>\nType: \u003Ctype> | Status: \u003Cstatus> | Owner: \u003Cowner>\n```\n\nThis adapter does not create the PR — it formats the description. The caller creates the PR with the output.\n\n### Adapter: session\n\nRender the doc's body (everything after the frontmatter) back into the chat session. Accept content directly in context; a source file is optional. Do not allocate scratch or artifacts for this adapter. **No file is written, no issue is created, no frontmatter is updated.** This is the \"think with me\" edition — the same manuscript every other adapter publishes, just printed instead of persisted. Optionally prepend a one-line header derived from `title:`\u002F`type:`. There is no dedup for this adapter.\n\n### Adapter: notion\n\nCreate a Notion page via the MCP Notion tool:\n\n1. Map frontmatter to Notion properties:\n   - `title:` → page title\n   - `type:` → select property\n   - `status:` → select property\n   - `tags:` → multi-select property\n   - `created:` → date property\n2. Set page body to the markdown content after frontmatter.\n3. After creating, add the Notion page URL to the source doc's `links:` frontmatter field only when the source is not a canonical artifact. For a canonical artifact, preserve it and record the URL in the current-owner private publication receipt.\n\nRequires the Notion MCP server to be configured. If not available, report the error clearly.\n\n## Step 3: Dry Run\n\nWhen `--dry-run` is set, show exactly what would happen without doing it (including the result of Step 1 validation, the resolved adapter\u002Fplane — with any plane-fit advisory — and, in family mode, the per-doc validation verdicts). For `--to artifacts`, do not allocate scratch\u002Fartifact paths, copy, promote, write a receipt, or mutate a destination during dry-run:\n\n```\nDry run: \u002Fclaudna:publish doc.md --to github-issue --repo example-repo\n\nHouse style: OK (type=audit, skeleton valid)\nWould create GitHub issue:\n  Repo: example-org\u002Fexample-repo\n  Title: Spotify API Rate Limits & Quirks\n  Labels: api, spotify, rate-limits\n  Dedup: 3 queries vs OPEN issues, --limit 20 each — \"rate-limits\" 2 hits,\n         \"429 backoff\" 0 hits, \"throttling\" 5 hits; all under limit.\n         No open match. Closed issues not searched.\n  Body: [243 chars, first line: \"Spotify enforces 30 req\u002Fsec per app...\"]\n\nNo changes made.\n```\n\n## Rules\n\n- **Never modify the doc body.** Only the documented frontmatter updates are allowed for noncanonical sources. Canonical artifacts remain immutable during publication; record returned links in the private receipt.\n- **Validate before publishing.** Invalid frontmatter or a missing body skeleton = no publish.\n- **One source of truth.** The markdown file is authoritative. Published outputs (issues, Notion pages) are copies — they may go stale.\n- **Report what you did.** After every publish, output: destination, URL\u002Fpath, and any frontmatter updates made.\n- If an adapter fails (auth error, missing repo, MCP not configured), report the error verbatim. Don't fabricate success.\n\n$ARGUMENTS\n","# Publish\n\n> **Codex:** Read `..\u002F_shared\u002Fcodex-tools.md` before following this skill. Apply its tool, root and dispatch mappings throughout.\n\nMarkdown-first, output-last. Takes a doc with frontmatter and publishes it to the right destination. The doc is always the source of truth — \u002Fclaudna:publish is just the adapter.\n\nThe default destination is the current native session's private `artifacts` area. Other destinations are explicit exports; native receipts and consumer acceptance remain merge\u002Frelease gates. Resolve the loaded package root through [`..\u002F_shared\u002Fclaudna-root.md`](..\u002F_shared\u002Fclaudna-root.md); examples use the actual `python3 -B \u003Cclaudna-root>\u002Flib\u002Fclaudna\u002Fsession_store` entrypoint.\n\n**This skill is the single output sink.** Analysis\u002Fplanning skills are *authors*: they produce a markdown doc with valid frontmatter and the house-style body skeleton, then hand it to \u002Fclaudna:publish. \u002Fclaudna:publish is the *publisher*: it enforces house style, dedups per-medium, and routes the one manuscript to whichever edition the caller asked for. Skills must never call `gh issue create` \u002F `gh pr create` themselves — they delegate here. The canonical house-style spec (frontmatter schema, per-type body skeleton, label taxonomy) lives in `..\u002F_shared\u002Foutput-guide.md`; this skill enforces it.\n\n## Arguments\n\nParse `$ARGUMENTS` at invocation:\n- **First positional arg:** Path to the source markdown file — or, for artifacts\u002Fdocs family mode, a directory holding one `00_*.md` master plus `NN_*.md` phase docs. Required except for `--to session`, which may receive the document directly in context without a file.\n- `--to \u003Cdest>`: Destination adapter. One of: `artifacts` (default), `vault`, `docs`, `github-issue`, `github-pr`, `session`, or `notion`.\n- `--dir \u003Cpath>`: docs adapter only — the target directory under `documentation\u002F` (the calling skill knows its category; registry in `..\u002F_shared\u002Fdocumentation-standard.md` §2). Required with `--to docs`.\n- `--update \u003Cissue#|url>`: Replace the named GitHub issue's body instead of creating anything. Implies `--to github-issue` — the only adapter with an update path — so `--to` may be omitted. See \"In-place update\" under the github-issue adapter.\n- `--repo \u003Cname>`: Target repository (for github adapters).\n- `--dry-run`: Show what would be published without doing it.\n\n---\n\n## Step 1: Read and Validate Source (house style)\n\nFor an in-context `session` document, validate its supplied content below without allocating files. **Before reading any source content**, resolve each explicitly selected source file or asset path (including symlink aliases) and determine whether it is a canonical artifact under the effective root. If it is, validate that exact absolute path and owner with the existing `continuity artifact-path` explicit-path form shown under the artifacts adapter below. Apply this gate to every canonical source for every destination adapter, including files individually selected from a family; never blanket-read a directory or read a canonical payload before its path is authorized. Validate current-session and other-session canonical paths. A current-owner private\u002Fmanual artifact is permitted; another owner's source requires a public, bounded scope. Missing, private, denied, stale, or otherwise uncertain validation means stop before content read, preserve the source, and report partial\u002Funavailable. Noncanonical scratch\u002Fuser sources follow the existing Step 1 reads and validation below.\n\nAfter the gate, read the allowed source markdown file. Parse YAML frontmatter. Validation is **deep** — a malformed manuscript is never published. If any check below fails, report the specific errors and stop. (Directory source: this step runs per doc via the artifacts\u002Fdocs family loop.)\n\n### 1a. Frontmatter schema\n\nValidate required fields exist and are well-formed:\n\n| Field | Rule |\n|-------|------|\n| `title` | non-empty string |\n| `type` | a valid note type — vocabulary table in `..\u002F_shared\u002Foutput-guide.md` §3 (the repo's only enum table, rendered from the Claudron SSOT) |\n| `status` | valid for the `type` per the §3 vocabulary table: canonical values pass silently; accepted legacy values (e.g. `active` on a knowledge doc) pass with a one-line mapping note — never a rejection |\n| `owner` | non-empty string |\n| `created` | valid `YYYY-MM-DD` |\n\nOptional fields: `tags` (→ issue labels), `repos` (→ vault dir + repo inference), `links` (publish writes the destination URL back here for editable noncanonical sources), `updated`, `expires`, `description`.\n\n**Canonical artifact source rule:** once a file is a canonical artifact, its content and frontmatter remain unchanged during later exports. In particular, do not add an issue, Notion, or other destination URL to that canonical source. For an actual returned non-chat outcome, record the destination in a private receipt under the current session's artifact area; this applies to every destination adapter and never copies the canonical source. A failed or uncertain destination may be recorded only with its actual failed\u002Funknown status, never as success. Session\u002Fchat output and dry-run remain mutation-free and create no receipt. A scratch export edition derived from a canonical source retains that source's ownership\u002Fprivacy gate and receipt obligation: record the canonical source hash plus the rendered edition hash and formatting\u002Fcross-link changes. Copying into scratch never bypasses canonical protection. Existing write-back behavior remains available for independently authored noncanonical user sources where the adapter below specifies it.\n\nPass-through fields (accepted, never rejected, never required — output-guide §3): `maturity`, `schema_version`, and any `x-*`-prefixed field. Publish carries them through untouched and never validates their values.\n\n### 1b. Body skeleton (per `type:`)\n\nThe body must match the house-style skeleton for its `type:`. This is keyed off `type:` (≤6 types) — publish validates the *skeleton*, never the prose, and never rewrites the body.\n\n- **`audit`, `review`, `plan`** — must contain the implementation-ready skeleton (see `..\u002F_shared\u002Foutput-guide.md` Section 4.1):\n  `## Summary`, `## Evidence`, `## Implementation Plan` (with `### Dependencies`, `### Blocks`, `### Steps`), `## Test Plan`, `## Verification Checklist`, `## What NOT To Do`, `## Context`.\n  **Hard gate:** the `## Implementation Plan` heading and its `### Steps` subsection MUST be present. This is the contract `\u002Fclaudna:build --source github` depends on to tell an implementable issue from a findings-only one — without it, `--auto` implementation blocks. Reject the publish if missing.\n- **`decision`, `knowledge`, `runbook`** — require a non-trivial body (not just frontmatter) and a leading `#`\u002F`##` heading. No fixed section gate (see `..\u002F_shared\u002Fdocumentation-standard.md`); validate presence, not structure.\n\n**Master-doc exception (artifacts and docs adapters):** a `00_*.md` doc validates like the knowledge tier — frontmatter + non-trivial body + leading heading, no §4.1 skeleton gate — even when its `type:` is `audit`\u002F`review`\u002F`plan`, whether it arrives as a family member (directory source) or alone (single-doc source: retros, dashboards, findings reports). Masters and standalone reports are inventories, not implementation plans; the skeleton hard gate exists for build readiness, which is a property of the `NN_*` phase docs (which validate in full). This exemption is the design, not a workaround.\n\n---\n\n## Step 2: Route to Adapter\n\nThe disk-backed adapters serve distinct planes — the plane doctrine and which-door table live in `..\u002F_shared\u002Fdocumentation-standard.md`:\n\n- **`vault`** → the shared-docs vault (cross-project referential knowledge; INDEX-discovered)\n- **`docs`** → the current repo's `documentation\u002F` tree (work-in-flight + repo-coupled records; git\u002FPR-discovered)\n- **`artifacts`** → generated finished output in the current native session's private artifact area; the default\n\n### Adapter: artifacts (default)\n\nUse this adapter when no destination is specified or the caller selects `--to artifacts` (workflow `--output artifacts`). It stores selected finished output in the current session's private artifact area. It does not publish a global pointer or make artifacts broadly discoverable.\n\n**Identity and allocation.** Obtain the current session ID and host from the qualified native runtime source. Never infer identity from cwd, time, an operation ID, a filename, or a guessed value. Resolve the loaded plugin root via `..\u002F_shared\u002Fclaudna-root.md`, then call the existing CLI:\n\n```bash\npython3 -B \"\u003Cclaudna-root>\u002Flib\u002Fclaudna\u002Fsession_store\" scratch \\\n  --session \"\u003Cverified-native-sid>\" --host \"\u003Cprovider>\" --label \"publish-artifacts\"\npython3 -B \"\u003Cclaudna-root>\u002Flib\u002Fclaudna\u002Fsession_store\" paths \\\n  --session \"\u003Cverified-native-sid>\" --host \"\u003Cprovider>\" --kind artifacts --create\n```\n\nAllocate scratch only when promotion or working files need it; reuse a caller's scratch with cleanup left to that owner. Use only the exact returned scratch and artifact paths. `scratch` allocates private temporary work; `paths --kind artifacts --create` resolves\u002Fcreates the private durable area. A missing, conflicting, or unverified identity, or an ordinary permission failure, makes this route partial\u002Funavailable: stop the artifact write and report the reason. Do not fall back to an OS temp path or claim the host is unsupported. A dry run does neither allocation nor writes. The `session` adapter remains chat-only and does not persist files.\n\n**Input and validation.** Accept a single finished markdown file or a family with exactly one `00_*.md` master and one or more `NN_*.md` phases. Preserve Step 1 validation, including the master-doc presence-only exception, and the docs adapter's all-or-nothing family validation. Non-markdown assets may be included only when explicitly selected as finished output. Never copy the surrounding scratch tree, credentials, or unrelated private files.\n\nIf the selected input is already a canonical artifact, validate its exact known path before reading its content, whether it belongs to the current session or another session. Pass the current session\u002Fhost, an explicit scope, the source session ID, and that absolute path to the existing CLI; the explicit-path form does not use `--workflow`:\n\n```bash\npython3 -B \"\u003Cclaudna-root>\u002Flib\u002Fclaudna\u002Fsession_store\" continuity artifact-path \\\n  --session \"\u003Ccurrent-sid>\" --host \"\u003Cprovider>\" --scope \"\u003Cscope>\" \\\n  --from-session \"\u003Csource-sid>\" --path \"\u003Cabsolute-source-path>\" --json\n```\n\nProceed only if the result validates that same path and ownership. A current-owner private\u002Fmanual artifact is permitted. Another owner's artifact requires a public, bounded scope. Missing, private, denied, or unverifiable ownership is denied before content read. This validation is for the explicitly selected path; it does not require or mutate a global pointer. For a same-session source, use its exact canonical path and do not create a replacement merely to republish it. Apply the same gate to canonical inputs routed to vault, docs, GitHub, Notion, or any other adapter. Do not copy a canonical source into a new artifact location merely to export it; store only the current-owner private publication receipt described above.\n\n**Promotion of scratch output.** Leave a selected source that is already canonical in place. For a new output, promote only the validated selected file\u002Ffamily and explicitly selected finished assets. Do not overwrite an existing canonical target: if it already contains identical bytes, report it as already canonical; if content differs, stop and surface the conflict. Stage within the private artifact directory on the same filesystem, retain ordinary private permissions (directories `0700`, files `0600`), hash each source, copy to staging, verify hashes, then atomically install into an absent canonical destination without replacement and verify final hashes. A concurrent destination collision is a conflict: retain staging and the existing canonical bytes. A pre-check followed by an overwriting rename is insufficient. Remove the exact allocated scratch only after all writer children have actually exited and verification succeeds. On failure or an uncertain writer, preserve scratch and report partial; never clean by glob or age.\n\n**Canonical export receipts.** For an actual (non-dry-run) invocation of any adapter other than `session`, preserve each canonical source and send only the explicitly selected finished docs\u002Fassets through the selected adapter. Before reading, publishing, or exporting the canonical source, resolve the current session's private receipt destination with `paths --kind artifacts --create` using the verified current SID\u002Fhost; if that identity or ordinary permission check fails, stop before destination mutation and report partial\u002Funavailable. After an actual returned result, write a private receipt owned by the current session under that artifact area, recording each source path and content hash, destination, and actual returned result (URL\u002Fpath\u002Fstatus). Use a unique receipt file with ordinary private permissions; do not create a shared ledger. If receipt storage fails after an external result, preserve the source and report that the result occurred but receipt persistence failed; do not claim the receipt exists. Do not write a receipt during dry-run, session\u002Fchat output, or for a result that did not occur. A genuine failed\u002Funcertain destination may be recorded only with its actual failed\u002Funknown status. The github-pr adapter formats a body only, so its returned result is formatting output unless the caller separately creates a PR and returns its URL.\n\nNative host receipts and consumer acceptance remain pending before merge\u002Frelease. This source contract is draft implementation, not native acceptance. Preserve that distinction in qualification receipts.\n\n### Adapter: vault (explicit export)\n\nThis plane has two backends — a Claudron vault (engine) and a raw tree (fallback). Run the **detection ladder in `..\u002F_shared\u002Fclaudron-engine.md` §1** first, then route:\n\n**Engine path — verdict present-with-vault.** Route the finished doc through Claudron rather than writing files directly; map its frontmatter onto a capture call:\n\n```bash\n# provenance (flags-capable engine only — see below): source_url and source_type ride in the finding file\nclaudron capture --stdin --json \u003C \u003Cfinding-file>\n```\n\nWrite the finding as JSON to `\u003Cfinding-file>`, a file in `\u003Cscratch>` (`..\u002F_shared\u002Forchestration-guide.md` §1), with the Write tool first (`type`, `title`, `body`, `tags`, `project`; `\u002Fclaudna:capture` Step 4): the title and body never go on the command line. `project` comes from the doc's `repos:` \u002F `--repo` (omit if unscoped). Validate the envelope (claudron-engine.md §2) and branch on `data.action`: `created` → report `data.path`; `suggest_update` \u002F `suggest_supersede` → surface `data.reason` and the existing note to the caller (the engine's index-backed dedup replaces the raw adapter's file-compare); `rejected` (exit 1) → surface the validation errors. An engine failure *during* capture (exit 3 or an unrecognized envelope) degrades to the fallback path below, per claudron-engine.md §3 — say so. Do **not** run `\u002Fclaudna:index` — the vault is engine-indexed (documentation-standard §10). Maturity is never set here; the engine stamps `draft`.\n\n**Provenance (capability-probed).** If the doc's frontmatter carries `source_url` \u002F `source_type` (SCHEMA optional fields), put them in the finding file as `source_url` \u002F `source_type` — but **only on a flags-capable engine**: `data.engine_version` present and ≥ **0.4.0** (the Claudron C2 release that added the flags; the same version probe `\u002Fclaudna:capture` Step 1 uses, and the same floor its PreCompact defer keys on). An older \u002F absent \u002F unreadable version omits them (it would reject the flags, exit 2). Provenance is **never** folded into the body here: that trailing `Source:` workaround was capture's alone, and the github-pr adapter's `Source:` footer is an unrelated surface.\n\n**Fallback path — verdict present-no-vault or absent** (frozen behavior). Emit the standard degradation notice first (`..\u002F_shared\u002Fclaudron-engine.md` §3.1 — quote the `\u002Fclaudna:publish --to vault` row), then write the doc to the raw-tree directory for its `type:`:\n\n| Type | Destination |\n|------|-------------|\n| plan | `shared\u002Fplanning\u002Factive\u002F` (or `completed\u002F` for terminal statuses) |\n| decision | `shared\u002Fdecisions\u002F` |\n| knowledge | `shared\u002Fknowledge\u002F\u003Crepo>\u002F` (requires `repos:` field or `--repo` flag) |\n| runbook | `shared\u002Frunbooks\u002F` |\n| audit, review | `shared\u002Fplanning\u002Factive\u002F` |\n\nA memory-home type (`entity`, `concept`, `person`, `project`, `practice`) has no raw-tree destination: Claudron files homes itself (`memory-homes`), and this fallback is frozen. Stop and say the doc needs the engine; in `--auto`, the outcome is `blocked`, with installing Claudron as the unblock.\n\nIf the file already exists, compare and warn before overwriting (the raw adapter's dedup). After writing: (1) run `\u002Fclaudna:index` on the destination to update INDEX.md; (2) report the path. In `--auto`, the fallback sets `artifacts.engine: \"fallback\"` and puts the §3.1 notice verbatim in `errors[]` (claudron-engine.md §3) — the degradation is never inferred from `artifacts.engine` alone.\n\n**Plane-fit advisory** (either path): a `plan`\u002F`audit`\u002F`review` doc landing vault-ward gets a one-line note — \"unusual plane for this type: generated planning normally stays in private session artifacts; a repository edition is an explicit docs export\". Advisory only, never a block — fleet workflows legitimately share plans vault-side.\n\n### Adapter: docs\n\nWrite the doc — or doc family — into the current repo's `documentation\u002F` tree, the per-project plane. The author retains its canonical output in `\u003Cartifacts>` (`..\u002F_shared\u002Forchestration-guide.md` §1) and hands it here; publish is the single **placement path for finished docs** on this plane (status-marker write-backs and archiving by `\u002Fclaudna:build` are the documented exceptions).\n\n- `--dir \u003Cpath>` is **required** and must resolve under `documentation\u002F`. Reject anything outside it. Create the directory if it doesn't exist (the Write tool creates parents automatically) — don't fail on missing directories.\n- **Single-doc mode** (source is a file): validate per Step 1, write into `--dir`, report the path.\n- **Family mode** (source is a directory): the source holds **exactly one** `00_*.md` master + `NN_*.md` phase docs (the shape forge and the audit lenses produce); any other `.md` file fails the family (zero or multiple `00_*` files likewise); only explicitly selected finished non-markdown assets (screenshots, assets) copy through; never copy the surrounding directory or private working material. Loop per doc: phase docs validate against the full Step 1 contract including the §4.1 skeleton hard gate; the master validates under the master-doc exception (Step 1b). Validation reads are bounded — frontmatter (first ~15 lines) plus a Grep for the required section headings decide every check; never pull a family's full prose into context (the orchestration guide's context-window rules apply to the publishing orchestrator too). Any doc failing validation fails the whole family — report every error, write nothing (no partial families). On success, write all docs into `--dir` preserving filenames; report the directory and doc count.\n- **No INDEX step.** The docs plane is git\u002FPR-discovered — never run `\u002Fclaudna:index` here; INDEX.md is the vault plane's discovery layer.\n- **Dedup:** if a target file already exists, compare (bounded — same read rules as validation) and warn before overwriting (same rule as the vault adapter).\n- **Plane-fit advisory:** a `knowledge`\u002F`runbook` doc landing here gets a one-line note — \"unusual plane for this type: cross-project reference knowledge may belong in an explicitly selected vault edition\". Advisory only, never a block.\n\n### Adapter: github-issue\n\n**Dedup first (mandatory).** A dedup that silently misses is exactly the failure it exists to\nprevent, so this step is bounded on purpose and **states its bound in the output**. Run it\nbefore creating, then apply the decision rules in `..\u002F_shared\u002Foutput-guide.md` Section 4.5.\n\n**1. Pick 2–3 deliberately different terms** from the doc's title, tags and cited files. GitHub\nissue search is *lexical, not semantic* — it cannot match a duplicate whose filer chose different\nwords than you did. Rephrasing toward the symptom does not fix that, so vary the vocabulary\ninstead:\n\n| Term | Draw it from | Why |\n|---|---|---|\n| **Component** | a file, function, script or module name in the doc | strongest — file and symbol names are the one vocabulary two filers reliably share |\n| **Symptom** | what the reader observes going wrong | matches a duplicate filed from the outside in |\n| **Synonym** | the same defect said another way | the coverage the other two miss |\n\n**2. Run one query per term — separate commands, one term each.** Write each term to its own file in `\u003Cscratch>` with the Write tool first (`\u003Ccomponent-file>`, `\u003Csymptom-file>`, `\u003Csynonym-file>`); a term never goes into the command itself.\n\n```bash\ngh issue list --repo \u003Cowner>\u002F\u003Crepo> --search=\"$(cat \u003Ccomponent-file>)\" --state open --limit 20 --json number,title,url\ngh issue list --repo \u003Cowner>\u002F\u003Crepo> --search=\"$(cat \u003Csymptom-file>)\"   --state open --limit 20 --json number,title,url\ngh issue list --repo \u003Cowner>\u002F\u003Crepo> --search=\"$(cat \u003Csynonym-file>)\"   --state open --limit 20 --json number,title,url\n```\n\n**One term per query is the whole point of running three.** GitHub ANDs the words inside a\n`--search` string, so `--search \"dedup limit truncation\"` is a *single* search for issues\ncontaining all three words — it is not three searches, and it is **narrower than any one of\nthem alone**. Three terms in one query is the opposite of the coverage this step is asking for.\n\nRun each command unpiped and read its output. A `gh` call piped into anything reports the\n*pipe's* exit status, so a failed search becomes an empty result that passes every check below.\n\n**3. Check each count against the limit** before drawing any conclusion from it. The count must\nbe **strictly below the `--limit` you passed**.\n\n- **Count \u003C limit** → complete for that term. Its hits are the whole open match set, and a zero\n  is a real zero.\n- **Count == limit** → **truncated.** What it returned is still real — a duplicate you can see is\n  a duplicate, so act on it. What a truncated query cannot support is the **negative**: you\n  cannot tell \"no issue in this repo matches\" from \"none of the first 20 match\". Reporting *no\n  duplicate found* on the strength of a query that came back at the limit is a false negative,\n  not a clean result. Narrow the term (a filename or a symbol rather than a common word) or\n  raise `--limit`, re-run, and report both what you changed and the new count.\n\n**4. State the bound with the result** — every query verbatim, its count, the limit it ran under,\nand what was outside the search. \"No duplicate found\" is never the whole claim; \"no *open* match\nfor *these terms*\" is.\n\n```\nDedup: 3 queries against OPEN issues in \u003Cowner>\u002F\u003Crepo>, --limit 20 each.\n  \"\u003Ccomponent>\" → 2 hits (under limit)\n  \"\u003Csymptom>\"   → 0 hits (under limit)\n  \"\u003Csynonym>\"   → 7 hits (under limit)\n  Verdict: no open issue matched. Closed issues were not searched.\n```\n\nThen apply §4.5 to whatever the searches returned:\n\n- Exact match → prefer offering `--update` of the existing issue (§4.5); skip and report its URL only if the caller declines.\n- Related but different → create and add `Related: #NNN` to the body.\n- Same pattern, different location → prefer adding to an umbrella issue.\n\nThen create the issue:\n\n```bash\ngh issue create \\\n  --repo \u003Cowner>\u002F\u003Crepo> \\\n  --title \"$(cat \u003Ctitle-file>)\" \\\n  --body-file \u003Cbody-file> \\\n  --label \"$(cat \u003Clabels-file>)\"\n```\n\nWrite the title, the markdown body after the frontmatter, and the comma-separated labels to those three files, in `\u003Cscratch>`, with the Write tool first. Text in them never goes into the command itself.\n\nLabels come from `tags:` — skills express severity\u002Fpriority as tags (`priority:critical`, `security`, `auto-audit`, …); publish maps `tags` → `--label` and creates any missing labels. The `--repo` flag is required; if `repos:` is set in frontmatter with exactly one repo, infer from that.\n\nAfter creating:\n1. Add the issue URL to the source doc's `links:` frontmatter field only when the source is not a canonical artifact. For a canonical artifact, preserve it and record the URL in the current-owner private publication receipt.\n2. Report the issue URL.\n\n**In-place update (`--update \u003Cissue#|url>`).** When the caller names an existing issue — a re-forged plan body, an epic gaining its phase-issues table, a corrected audit — replace that issue's body instead of creating anything:\n\n```bash\ngh issue edit \u003Cnumber> --repo \u003Cowner>\u002F\u003Crepo> --body-file \u003Crendered-body-file>\n```\n\nRules: dedup is skipped (the target is explicit); the title is never changed (`gh issue edit --body-file` only — retitling stays a manual act); labels are additive only (`--add-label` for new `tags:`, never removing existing ones); report the issue URL and note \"updated in place\". The exact-match dedup rule lives in `..\u002F_shared\u002Foutput-guide.md` §4.5 and routes here: an exact match prefers an offered `--update` over a skip.\n\n### Adapter: github-pr\n\nFormat the doc as a PR description body. Write the formatted text to a file in `\u003Cscratch>` with the Write tool, for the caller to pass as `gh pr create --body-file \u003Cfile>`:\n\n```\n## Summary\n\n\u003Cfirst paragraph of doc body>\n\n## Details\n\n\u003Crest of doc body>\n\n---\nSource: \u003Csource file path>\nType: \u003Ctype> | Status: \u003Cstatus> | Owner: \u003Cowner>\n```\n\nThis adapter does not create the PR — it formats the description. The caller creates the PR with the output.\n\n### Adapter: session\n\nRender the doc's body (everything after the frontmatter) back into the chat session. Accept content directly in context; a source file is optional. Do not allocate scratch or artifacts for this adapter. **No file is written, no issue is created, no frontmatter is updated.** This is the \"think with me\" edition — the same manuscript every other adapter publishes, just printed instead of persisted. Optionally prepend a one-line header derived from `title:`\u002F`type:`. There is no dedup for this adapter.\n\n### Adapter: notion\n\nCreate a Notion page via the MCP Notion tool:\n\n1. Map frontmatter to Notion properties:\n   - `title:` → page title\n   - `type:` → select property\n   - `status:` → select property\n   - `tags:` → multi-select property\n   - `created:` → date property\n2. Set page body to the markdown content after frontmatter.\n3. After creating, add the Notion page URL to the source doc's `links:` frontmatter field only when the source is not a canonical artifact. For a canonical artifact, preserve it and record the URL in the current-owner private publication receipt.\n\nRequires the Notion MCP server to be configured. If not available, report the error clearly.\n\n## Step 3: Dry Run\n\nWhen `--dry-run` is set, show exactly what would happen without doing it (including the result of Step 1 validation, the resolved adapter\u002Fplane — with any plane-fit advisory — and, in family mode, the per-doc validation verdicts). For `--to artifacts`, do not allocate scratch\u002Fartifact paths, copy, promote, write a receipt, or mutate a destination during dry-run:\n\n```\nDry run: \u002Fclaudna:publish doc.md --to github-issue --repo example-repo\n\nHouse style: OK (type=audit, skeleton valid)\nWould create GitHub issue:\n  Repo: example-org\u002Fexample-repo\n  Title: Spotify API Rate Limits & Quirks\n  Labels: api, spotify, rate-limits\n  Dedup: 3 queries vs OPEN issues, --limit 20 each — \"rate-limits\" 2 hits,\n         \"429 backoff\" 0 hits, \"throttling\" 5 hits; all under limit.\n         No open match. Closed issues not searched.\n  Body: [243 chars, first line: \"Spotify enforces 30 req\u002Fsec per app...\"]\n\nNo changes made.\n```\n\n## Rules\n\n- **Never modify the doc body.** Only the documented frontmatter updates are allowed for noncanonical sources. Canonical artifacts remain immutable during publication; record returned links in the private receipt.\n- **Validate before publishing.** Invalid frontmatter or a missing body skeleton = no publish.\n- **One source of truth.** The markdown file is authoritative. Published outputs (issues, Notion pages) are copies — they may go stale.\n- **Report what you did.** After every publish, output: destination, URL\u002Fpath, and any frontmatter updates made.\n- If an adapter fails (auth error, missing repo, MCP not configured), report the error verbatim. Don't fabricate success.\n\n$ARGUMENTS\n",{"name":5,"requires":42,"description":7,"argument-hint":46,"user-invocable":47},[43],{"cli":44,"reason":45},"claudron","Optional — `--to vault` routes the doc through `claudron capture` when the engine is present; without it, that one adapter degrades per the standard notice in ..\u002F_shared\u002Fclaudron-engine.md §3.1 and writes the frozen raw tree. Every other adapter is unaffected","\u003Csource-file-or-dir> [--to artifacts|vault|docs|github-issue|github-pr|session|notion] [--dir \u003Cpath>] [--update \u003Cissue#|url>] [--repo \u003Cname>] [--dry-run]",true,"main","17096951d140527accf05a94d7269b77e64a9197","skills\u002Fpublish",1,"https:\u002F\u002Fgithub.com\u002FClaudfather\u002FclauDNA","https:\u002F\u002Fgithub.com\u002FClaudfather","https:\u002F\u002Fcrog.gg","Rise of the machines","2026-11-12 21:12:12",{"source":8,"skillName":5,"commands":58,"prompt":68,"zipAvailable":47},[59,62,65],{"tool":60,"command":61},"npx","npx skills add Claudfather\u002FclauDNA --skill publish",{"tool":63,"command":64},"bunx","bunx skills add Claudfather\u002FclauDNA --skill publish",{"tool":66,"command":67},"pnpm","pnpm dlx skills add Claudfather\u002FclauDNA --skill publish","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FClaudfather\u002FclauDNA\u002Fblob\u002Fmain\u002Fskills\u002Fpublish\u002FSKILL.md",[],[71,96,106,129,154,171],{"skillNo":72,"name":73,"nameZh":6,"description":74,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":75,"categories":76,"keywords":77,"publishedAt":37},"01M71T1STJ99BE1C0JYHCQW0XN","example-review","Use when you want to review pull requests with detailed, actionable feedback on code quality, correctness, and maintainability.","https:\u002F\u002Fgithub.com\u002FClaudfather\u002FclauDNA\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fvalid-package\u002FSKILL.md",[],[27,78,79,80,81,82,83,84,85,86,30,87,88,89,90,91,92,93,94,95],"example","example review","actionable","pull requests","with","code","correctness","Bash","you","use","gh","gh pr","diff","view","pr","code quality","feedback","pull",{"skillNo":97,"name":98,"nameZh":6,"description":99,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":102,"publishedAt":37},"01M71T1RMCD30MAJC954JC7580","bad-skill","Too short","https:\u002F\u002Fgithub.com\u002FClaudfather\u002FclauDNA\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Ffailing-package\u002FSKILL.md",[],[103,104,105],"bad","bad skill","short",{"skillNo":107,"name":108,"nameZh":6,"description":109,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":110,"categories":111,"keywords":112,"publishedAt":37},"01M71T1NS97NJ2MQ993V7FBES7","worktree","Use when starting feature work that needs isolation from the current workspace, or when running multiple Claude sessions in parallel on different branches — creates and manages git worktrees. For fetching latest main into every existing worktree and branch across your sibling repos, use \u002Fclaudna:sync-branches instead.","https:\u002F\u002Fgithub.com\u002FClaudfather\u002FclauDNA\u002Fblob\u002Fmain\u002Fskills\u002Fworktree\u002FSKILL.md",[],[108,113,114,115,116,117,118,119,120,121,18,122,30,123,48,124,125,126,127,128],"sync","repos","git","isolation","running","sessions","worktrees","work","across","git worktrees","claude sessions","branches","branch","parallel","for","feature",{"skillNo":130,"name":131,"nameZh":6,"description":132,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":133,"categories":134,"keywords":135,"publishedAt":37},"01M71T1HNVG1CZY8P904P6RB7P","weigh-development-paths","Use when at a development junction with multiple viable approaches — architecture choices, refactoring strategies, where to put new code, or which pattern to follow. Triggers on 'which approach', 'how should I', 'Option A vs B', or any point where the next step isn't obvious and the wrong choice creates rework.","https:\u002F\u002Fgithub.com\u002FClaudfather\u002FclauDNA\u002Fblob\u002Fmain\u002Fskills\u002Fweigh-development-paths\u002FSKILL.md",[],[136,137,138,139,140,141,142,143,144,145,146,147,148,83,30,149,150,151,152,153],"development","weigh development paths","paths","next step","path","refactoring","choice","pattern","at","how","next","strategies","architecture","auto","new","junction","option","which",{"skillNo":155,"name":156,"nameZh":6,"description":157,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":158,"categories":159,"keywords":160,"publishedAt":37},"01M71T1ECV1T5E168GH70AY5B3","verify-completion","Use when about to claim work is complete, fixed, or passing -- requires running verification commands and confirming output before making any success claims.","https:\u002F\u002Fgithub.com\u002FClaudfather\u002FclauDNA\u002Fblob\u002Fmain\u002Fskills\u002Fverify-completion\u002FSKILL.md",[],[161,162,163,164,117,165,166,167,120,168,169,170,30,87],"verify completion","verify","claim","complete","true","commands","about","verification","claims","output",{"skillNo":172,"name":173,"nameZh":6,"description":174,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":175,"categories":176,"keywords":182,"publishedAt":37},"01M71T1BC1HA7XQH0Q1H574FYS","vercel","Use for Vercel operations — deploy to production or preview (or roll back), view, filter, or debug deployment logs, or check project status (deployments, domains, env vars, config). Replaces \u002Fvercel-deploy, \u002Fvercel-logs, \u002Fvercel-status.","https:\u002F\u002Fgithub.com\u002FClaudfather\u002FclauDNA\u002Fblob\u002Fmain\u002Fskills\u002Fvercel\u002FSKILL.md",[177],{"categoryNo":178,"categoryName":179,"taxonomyType":180,"taxonomyTypeDesc":181},"01JBSEEDCAT000000000000011","运维与部署","SCENARIO","使用场景",[173,183,184,185,186,187,188,189,190,87,191,165,192,193,194,195,127,91,196,197],"inspection","check","filter","env","logs","preview","debug deployment","debug","deployments","domains","deployment","env vars","project","project status","back"]