# Public Private Routing

> Enforces the firewall between a public knowledge store and per-client private stores by checking declared visibility, abstracting client/project identifiers by default, and running an independent publish-time grep against a maintained identifier list. Use before committing or publishing any page, and as a pre-commit/CI gate.

- Skill: `vamseeachanta/public-private-routing` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add vamseeachanta/public-private-routing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/vamseeachanta/public-private-routing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: CC-BY-4.0
- Author: vamseeachanta (https://skillmd.com/u/vamseeachanta)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/vamseeachanta/public-private-routing

---


# public-private-routing

> Template skill (doc 08, doc 07 §1/§4). The leak vector is not file copying —
> it is agents *writing about* private material. This skill is the machine-checked
> contract that catches it.

## Trigger
`/route-visibility <path-or-diff>`

## Preconditions
- A maintained **identifier list** exists: client names, project codes, internal
  path/host patterns, API-key shapes, personal-data patterns.
- Every page declares `visibility: public|private` (+ optional `client:`).

## Steps
1. **Declare-and-check visibility.** Read `visibility:` from frontmatter. Derived
   data from vendor-licensed/confidential sources MUST route private; only
   genuinely public-domain material routes public. Mismatch → block.
2. **Abstraction by default.** In any public-routed (or shared) page, client and
   project names are abstracted unless the fact is *publicly verifiable*. A
   concrete name in a public page without public corroboration → block.
3. **Publish-time grep.** Before content crosses the boundary, grep the actual
   content against the identifier list. **Do NOT delegate this to the agent that
   produced the content** — run it independently (a subagent once declared its
   own output clean while it contained client folder names).
4. **Raw-source firewall.** Assert no raw licensed/confidential source file is
   being committed — only derived parts plus opaque public source tokens or
   public-safe provenance bundle references.
5. **ACE wave-1 JSON/config/code-derived output.** Before any text, config, or
   code-doc candidate routes `public_llm_wiki`, require affirmative public
   clearance and the #63 public-output canary over the exact surface. Without
   clearance, demote to `private_sidecar`, `metadata_only`, or
   `excluded_no_ingest`.

## Verification
- Pre-commit hook + CI deny-list scan must pass (L3); a hit blocks the commit/merge.
- The grep is run by the gate, not self-reported by the producing agent.
- For ACE-derived public outputs, run
  `uv run python scripts/validate_ace_public_artifacts.py --scan-public-path <surface> --issue-comment-body-file <planned-comment.md>`
  over the exact docs, skill, workflow, review artifact, `mkdocs.yml`,
  `llm-wiki`, GitHub-public summary, issue closeout summary, or external
  publication surfaces before they cross the boundary.
- For this repo, run `bash scripts/legal/legal-sanity-scan.sh --all-tracked-public-surfaces`
  before publishing or closing public-surface work; use `--diff-only` for local
  staged/unstaged closeout checks.

## Cleanup
- n/a (gate).

## Incident appendix
| Rule | Why |
|---|---|
| Independent publish-time grep | Producing agent overclaimed "no confidential identifiers" |
| Abstraction by default | Names leak via generated prose, not file copies |
| Machine-checked visibility | Routing is a contract, not a convention |

