Powernode is a platform other people deploy. Facts that describe one deployment — its hostnames, internal IP ranges, hypervisor and VM ids, systemd unit ids, git remotes, operator mailboxes, break-glass paths — are irrelevant to every other deployment and a gratuitous disclosure on the public mirror. They never belong in a git-tracked file.
Their home is the deployment's own platform knowledge store, which is local to the deployment by construction (it lives in that deployment's database, behind that deployment's auth) and is recalled MCP-first by every executor, Claude or not.
| Kind of fact | Home | Recall |
|---|---|---|
| Generic procedure ("how a hub is reprovisioned", "how the watchdog works") | tracked docs (docs/operations/, an extension's docs/runbooks/) written with placeholders |
read the file / search_knowledge |
| This deployment's values (which host, which VM, which address, which remote) | platform knowledge, tags deployment + deployment-<topic>, access_level: account |
search_knowledge tag:deployment-<topic> |
| Claude-only, machine-local operator notes | CLAUDE.local.md (gitignored) |
loaded automatically, this machine only |
Placeholders in tracked docs: <hub-host>, <hub-vmid>, <hypervisor>, an
example.test name, an RFC 5737 address (192.0.2.x, 198.51.100.x, 203.0.113.x).
Public brand domains are not deployment identifiers and may appear in tracked docs.
Memories (tag memory, contract in knowledge-lifecycle.md) share this
access model: account-scoped, never global. SharedKnowledge private is a label, not an ACL:
search scopes by account only, so anyone who can search the account can read a private entry.
Two equivalent paths; both land in the same store with the same tags.
Directly, from any executor (MCP):
create_knowledge
title: "ops hub: host, VM, hypervisor"
content: "<the facts>"
content_type: "reference"
access_level: "account"
tags: ["deployment", "deployment-ops-hub"]
As local markdown (operators, bulk): write docs/operations/local/<topic>.md
(gitignored) and run, on the deployment's Rails:
cd server && bundle exec rails ai:seed_deployment_knowledgeEach file is upserted idempotently as deployment-<filename> (key-anchored, hash-detected
updates, same seeder as the guidance-* conventions). A file that names a private
extension is accepted: the source is gitignored and the entry is account-scoped, so the
gate that refuses such content for public guidance does not apply.
- Any session:
search_knowledge tags:["deployment-<topic>"]ortags:["deployment"]. Query the production connector; a sandbox store is unseeded and returnscount:0for the same call. - Loop-driven and platform agents are told to recall
deployment-*before touching infrastructure by the shared guardrails (Ai::DevLoop::LoopGuardrails::HEAD,Ai::Agent::BASE_GUARDRAILS). - The SessionStart digest carries the pointer for Claude sessions.
- Scan:
scripts/checks/deployment-identifier-check.sh(run byscripts/pattern-validation.shas a security-critical check) greps every file in the working tree that git would publish — tracked, PLUS untracked and not gitignored — in core and in each public extension submodule. Untracked files are in scope because a leak is authored before it is committed: a tracked-only scan passes for the author running it and fails for whoever runs it next (IMP-7bafaf99314d). - Edit-time hook:
.claude/hooks/deployment-identifier-check.shruns the same script on the file just written and blocks on a hit. - Patterns come from the gitignored
.claude/hooks/deployment-identifiers.local.txt, one POSIX extended regex per line. A guard against name leakage must not itself contain the names, so the list is deployment-local and the guard is a no-op where the list is absent. Operators write the list once per deployment; it is the only place the private values appear in the working tree.
Both paths are one implementation with two entry points (--file for the hook, tree mode
for the scan), so they cannot disagree.
- Private extensions (
extensions/private/*) are not published and are not scanned. - The guard is a regex over text. It catches the identifiers you list; it does not infer new ones. Add a pattern when a new deployment-specific name appears.
- Git history on the public mirror keeps whatever was pushed before a value was removed. The guard reduces forward exposure only.