Extract a sanitized shared team/company brain from a personal brain. Strips internal ratings, compensation, performance assessments, retention and political dyn
复制下面这句话,粘贴给 Claude Code、Codex、Cursor 等 AI 编程工具,它会读取安装说明并在你确认后完成安装。
请阅读 https://ai.atlankj.com/install/asset/gh-company-brainify-5687557bbcf9 ,按照其中的说明把「company-brainify」安装到你(当前 AI 工具)中。执行前先告诉我将运行的命令和写入的位置,等我确认。
查看 AI 将读取的安装说明正在读取 GitHub 原文…
内容来自 GitHub 原始文件,由原作者维护。在 GitHub 查看
Convention: see conventions/brain-first.md — discovery runs through the brain's own retrieval, not filesystem guesswork. The grep pipelines below TRIAGE;
gbrain queryfinds what keyword patterns miss.Convention: see conventions/test-before-bulk.md — sanitize 3-5 files, read the output yourself, then ramp. A bad bulk sanitization pass is worse than none: it looks done and isn't.
Convention: see conventions/regex-discipline.md — "is this sensitive?" is a judgment call, so the model decides per file. The grep patterns are earned triage/verification tools, never the judge.
Convention: see _brain-filing-rules.md — edits stay in the page's existing directory; the deletion log files date-keyed under
daily/.
Personal brains accumulate everything — company knowledge, meeting notes,
internal assessments, compensation details, management strategy, candid
opinions about the people you work with. When you stand up a shared team
brain from that personal brain (see docs/architecture/brains-and-sources.md
for the team-mount topology), all of that has to go. The knowledge is
valuable; the sensitive metadata is a liability.
Clean working-tree files alone are NOT enough: git history still carries every pre-sanitization version, and gbrain takes/facts carry evaluative claims outside the page prose. This skill handles all three surfaces — pages, takes/facts, and history.
Connecting or indexing an existing company repository without editing it is not
sanitization. For “connect our company brain” or “import an existing company
brain,” use the migrate (host-side) company workflow. On the trusted brain host,
start with gbrain sources inspect <path> --profile company-brain; follow
docs/guides/company-brain-ingestion.md for destination preview and approval.
Do not strip metadata or purge history merely to make an existing repository
searchable.
| Category | Examples |
|---|---|
| Internal scores/ratings | score:, rating:, skill:, or any vertical-specific *_score: frontmatter field; any numeric rating of a person |
| Compensation | Salary, equity, carry, option grants, comp changes, retention packages |
| Performance assessments | Strengths/weaknesses sections about employees, "at risk" flags, underperformance mentions, "picking up slack" references |
| Departure/retention | Who's considering leaving, who was convinced to stay, departure rumors, retention conversations |
| Management strategy | How-to-manage-someone sections, "the hard conversation" notes, scope/title management plans |
| Internal political dynamics | Who doesn't like whom, who's nervous about whom, adversarial relationships, power dynamics |
| Personal PII | Phone numbers, personal email addresses, home addresses, family or medical details, personal legal matters, personal-life details |
| Takes/facts | Any take or fact referencing the above categories — performance, comp, retention, weakness, management risk. Fact rows are DELETED from the page's Facts fence, never merely expired with gbrain forget |
| Category | Examples |
|---|---|
| Professional identity | Name, role, title, work email, LinkedIn |
| What they're building | Current projects, product work, technical contributions |
| Career arc | Prior companies, education, professional background (public info) |
| Professional beliefs | Their views on technology, strategy, product philosophy |
| Timeline of work | Meeting attendance, project milestones, launches (factual, not evaluative) |
| Skills/expertise | Technical capabilities, domain knowledge |
Sensitive content leaks far beyond people pages. The scan scope is:
people/ — the primary surface (frontmatter fields, assessment sections)meetings/ — transcripts and minutes with candid assessmentsdaily/ — daily notes referencing comp/performance/retention conversationscompanies/, projects/, analysis/ — cross-references to removed contentgbrain takes search)gbrain recall --grep)gbrain check-backlinks check confirms no page
still points at removed sectionsA pass that only covers people/ will certify a brain that still leaks.
All paths below are relative to the brain repo root:
BRAIN="$(gbrain config get sync.repo_path)"
cd "$BRAIN"
Retrieval discovery — hybrid search catches judgment-shaped content that no keyword pattern will:
gbrain query "compensation, equity, or salary discussions about team members" --limit 50
gbrain query "performance concerns, underperformance, or who is struggling" --limit 50
gbrain query "considering leaving, retention conversations, departure rumors" --limit 50
gbrain takes search "performance" --limit 50
gbrain recall --grep "salary"
Resolve every returned slug to its repo-relative file path and write the
paths into /tmp/brainify-scope.txt (one per line). This file is the
scope list; the structural pass below APPENDS to it — nothing later in
the procedure may truncate it, or the retrieval-discovered pages
silently drop out of scope.
Structural discovery — people files that belong to the company, plus keyword hits across the wider scan scope:
grep -rli 'company: *"acme-example"' people/ --include="*.md" | sort >> /tmp/brainify-scope.txt
grep -rli -E 'salary|equity|carry|retention|underperform|performance review|hard conversation' \
meetings/ daily/ companies/ projects/ analysis/ --include="*.md" 2>/dev/null >> /tmp/brainify-scope.txt
sort -u -o /tmp/brainify-scope.txt /tmp/brainify-scope.txt
Cross-reference against the company's public people page (website, LinkedIn) to catch files using different frontmatter conventions.
Count: wc -l /tmp/brainify-scope.txt
Prioritize by hit density (portable grep -E; no \b — BSD and GNU disagree):
while read -r f; do
hits=$(grep -c -i -E 'carry|salary|equity|comp change|departure|considering leaving|retention|underperform|picking up slack|performance review|management risk|hard conversation|nervou|score: *[0-9]|firing|fired|pip|probation|weakness' "$f" 2>/dev/null || true)
[ "${hits:-0}" -gt 0 ] && echo "$hits $f"
done < /tmp/brainify-scope.txt | sort -rn > /tmp/brainify-triage.txt
High-hit files need full judgment passes. Zero-hit files may only need frontmatter field removal — but they still get read (regex triages, the model judges).
Phase 3 is destructive: it strips content across many files, removes takes, and deletes fact rows. Two rules govern it.
Choose the target FIRST — copy, don't mutate the personal brain.
Standing up a NEW team brain (default, preferred): sanitize a STAGING COPY of the scanned directories, never the personal brain in place. The founder's personal brain is SUPPOSED to keep comp, performance, and candid notes — stripping them from the personal working tree destroys valuable private data. Copy the Phase-1 scope into a durable staging dir and edit THAT; Phase 5 Step 0 exports from the staging copy. Blast radius: none on the personal brain.
# Durable staging dir (NOT /tmp — same reasoning as the mirror backup).
STAGING="$HOME/.gbrain/backups/brainify-staging-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$STAGING" && chmod 700 "$STAGING"
for d in people meetings daily companies projects analysis; do
[ -d "$d" ] && rsync -a "$d/" "$STAGING/$d/"
done
cd "$STAGING" # all edits below happen here, not in sync.repo_path
Re-auditing an EXISTING shared brain: the shared brain IS the target, so
edits are in place on the SHARED repo (cd into the shared repo, never the
personal sync.repo_path). Fact-row removal + re-sync applies to the shared
source's DB.
Fire the data-loss-gate confirmation card BEFORE the bulk destructive edits begin. Both targets are destructive (the copy path removes content from the tree destined for the team; the in-place path removes content from a live brain). Pre-filled for Phase 3:
⚠️ DATA DELETION — Confirmation Required
What: strip sensitive content, remove takes, and delete fact rows across
[N files] in [STAGING COPY at <path> | the SHARED brain in place]
Count: [N files edited; T takes removed; F fact rows removed]
Location: [staging path OR shared repo path] — NOT the personal sync.repo_path
on the staging path
Why: preparing a sanitized tree for team access
Recoverable?
- [x] Personal brain untouched (staging-copy path) — re-copy to redo
- [ ] In-place shared-brain path: edits overwrite the live tree; git history is
the recovery line until Phase 5 purges it
Proceed? (yes/no)
Require a typed "yes"/"do it" per data-loss-gate; "ok"/"sure" are not consent.
Per test-before-bulk: do 3-5 files first, read the results, then ramp. For large sets (50+ files), batch into groups of 10-12 and spawn parallel subagents. Per file:
Decision rule: use Edit for surgical removal when only a few sections
need it. Use Write to rewrite the entire file only when sensitive content is
deeply interwoven throughout.
Facts: forget is NOT removal. gbrain forget <fact-id> expires a fact
— the row stays on the page's Facts fence struck through, and the DB still
serves it via --include-expired. An expired fact is retained, not gone.
For sanitization, sensitive fact rows must be ACTUALLY REMOVED: find them
(gbrain recall --grep), then delete the row from the page's Facts fence
(step 5), exactly like a sensitive take. On an in-place shared brain, the
page edit must then be re-synced (gbrain sync re-imports the edited page)
AND the facts index reconciled — sync's convergence contract covers page
import only; downstream fact extraction is explicitly decoupled
(src/commands/sync.ts, "CONVERGENCE CONTRACT"), so the DB keeps serving
the deleted row until the extract-facts reconcile runs. Trigger it
(gbrain sweep, or wait for the serve-resident sweep), then confirm with
gbrain recall --grep that the row is actually gone. An edited page over
an un-reconciled facts index still leaks through retrieval. forget alone
can never certify a brain clean.
After edits: on the staging-copy path the fact rows are removed by editing
the copied markdown directly (there is no live DB to re-sync yet — the team DB
is built fresh when Phase 5 Step 0 turns the export into a source). On the
in-place shared-brain path, run gbrain sync so the page content matches
the markdown, then reconcile and verify the facts index as above. Either way,
run gbrain check-backlinks check to catch pages still pointing at removed
content.
Re-run the Phase 2 triage — the count of flagged files should drop to (near-)zero. Then targeted greps:
# Rating fields remaining in frontmatter
grep -rn -E '^[a-z_]*(score|rating|skill)[a-z_]*: *[0-9]' people/ --include="*.md"
# Phone numbers
grep -rn -E '\+1[0-9]{10}|\([0-9]{3}\) [0-9]{3}-[0-9]{4}' people/ --include="*.md"
# Comp keywords (full scan scope, not just people/)
grep -rin -E 'carry|comp change|equity|salary' people/ meetings/ daily/ companies/ projects/ analysis/ --include="*.md" 2>/dev/null
# Management/performance
grep -rin -E 'considering leaving|departure rumor|underperform|picking up slack|hard conversation' people/ meetings/ daily/ companies/ projects/ analysis/ --include="*.md" 2>/dev/null
False positives (e.g. "carry the torch") are fine — manually confirm each remaining hit rather than tightening the pattern (regex-discipline).
Verify the tree that ships. On the staging-copy path, these greps run
against the sanitized $STAGING tree (which Phase 5 Step 0 turns into the
export) — the personal working tree is not what ships, so certifying it proves
nothing. For an in-place shared-brain re-audit, the shared repo's tree is the
shipped tree and this pass stands as-is.
Then the strongest check — the retrieval the team will actually use. Against
the sanitized brain/source (scope with --source <team-source-id> when the
shared source is mounted alongside personal content):
gbrain query "what is alice-example's compensation" --limit 10
gbrain query "who is underperforming or at risk of leaving" --limit 10
gbrain takes search "weakness" --limit 20
Every one of these must come back empty or with only keep-category content.
Clean files aren't enough if the repo has history: old commits still contain the sensitive versions.
Step 0 — preferred alternative (non-destructive). When standing up a NEW team repo, skip history rewriting entirely: the sanitized STAGING tree from Phase 3 becomes a fresh repo with fresh history. The personal repo keeps its full history AND its full working tree, untouched.
Export rule: nothing unscanned ships. Because Phase 3 copied ONLY the
scanned directories into $STAGING, the staging tree contains nothing the
sanitization pass didn't read — the include-only rule holds by construction.
Never copy extra directories in: everything outside the scan scope
(conversations/, originals/, sources/, inbox/) stays out. A whole-repo
copy is the classic leak — it ships raw transcripts, originals, and inbox
captures no pass ever read. To ship a new directory, add it to the scan scope
first (Phases 1-4) so it lands in $STAGING sanitized.
# The sanitized staging tree IS the export.
cd "$STAGING"
# Re-run the Phase 4 verification greps + retrieval checks INSIDE $STAGING —
# the staging tree is what ships, and it is the tree that must certify clean.
# ... Phase 4 greps against $STAGING ...
git init -b main
git add -A && git commit -m "Initial import — sanitized team brain"
git remote add origin <TEAM_REPO_URL>
git push -u origin main
Only when a shared repo ALREADY exists with sensitive history in it do you need the purge below.
Step 1 — target the SHARED repo, commit the clean tree, then mirror-clone.
The purge operates on the SHARED repo, NEVER on sync.repo_path (the personal
brain) — Step 0's guarantee that the personal repo keeps full history depends
on it. Clone the shared repo to a durable work dir, stay there for every step
below, and assert the target is not the personal repo before touching anything.
PERSONAL="$(gbrain config get sync.repo_path)"
mkdir -p "$HOME/.gbrain/backups" && chmod 700 "$HOME/.gbrain/backups"
WORK="$HOME/.gbrain/backups/brainify-purge-$(date +%Y%m%d-%H%M%S)"
git clone <SHARED_REPO_URL> "$WORK/shared"
cd "$WORK/shared"
[ "$(git rev-parse --show-toplevel)" != "$PERSONAL" ] \
|| { echo "target IS sync.repo_path (personal brain) — ABORT"; exit 1; }
# Apply the sanitized tree, then COMMIT it BEFORE the mirror clone. A mirror
# captures COMMITTED state only; if the clean tree lives only in volatile
# staging during the rewrite window, a crash loses the sanitization work.
# Committing makes the clean state durable and recoverable.
for d in people meetings daily companies projects analysis; do
[ -d "$STAGING/$d" ] && rsync -a "$STAGING/$d/" "./$d/" # or sanitize in place here
done
git add -A && git commit -m "Sanitize: strip sensitive content before history purge"
# Mirror-clone backup = the recoverability line on the card. Capture the path
# in a variable NOW and reuse it verbatim at purge time — a run crossing
# midnight must NOT recompute $(date) and false-abort on a mismatched name.
BACKUP_PATH="$HOME/.gbrain/backups/shared-brain-history-backup-$(date +%Y%m%d-%H%M%S).git"
git clone --mirror "$WORK/shared" "$BACKUP_PATH"
git -C "$BACKUP_PATH" log -1 >/dev/null || { echo "backup unreadable — ABORT"; exit 1; }
Verify the mirror exists and reads before presenting the card — it is the card's recoverability line.
Step 2 — STOP. Present the data-loss-gate confirmation card and wait. History rewrite + force-push is the most destructive operation in this skill: it permanently discards every prior version of the purged paths from the remote. Never run it without the card answered. Pre-filled for this operation:
⚠️ DATA DELETION — Confirmation Required
What: rewrite git history to remove all prior versions of [purged paths]
from the SHARED repo, then force-push to [remote/branch]
Count: [N commits rewritten; M files with history purged]
Size: [repo size before → expected after]
Location: [SHARED repo work dir; remote URL; branch]
Target check: this is the SHARED repo, verified ≠ personal sync.repo_path
($PERSONAL) — the personal brain's history is never rewritten
Why: prior commits contain pre-sanitization versions of pages that were
just cleaned — team access to the repo means team access to history
Recoverable?
- [x] Mirror-clone backup at $BACKUP_PATH
(verified: exists, `git -C "$BACKUP_PATH" log` works)
- [ ] NOT recoverable from the rewritten remote — old SHAs become unreachable
What we'd lose:
- all pre-sanitization history for the purged paths (edit trail, blame,
old versions)
- every existing clone breaks — all collaborators must re-clone
Alternative to deletion:
- fresh-history export to a NEW team repo (Step 0) — personal repo untouched
Proceed? (yes/no)
Per data-loss-gate: require a typed "yes" or "do it" — "ok", "sure",
"go ahead" are not consent. If the user asks a question, answer and re-present
the card. This gate is a routing convention, not a runtime enforcement —
nothing in gbrain mechanically blocks git filter-repo — which is exactly why
the agent following this skill must not skip it.
Step 3 — purge (only after the explicit typed yes). Requires
git filter-repo (not bundled with git; install separately). Run this ONLY
in the shared-repo work dir from Step 1 (cd "$WORK/shared"). NEVER run
git filter-repo or git push --force in sync.repo_path — the personal
brain's history must stay intact. The commands below reuse $WORK and
$BACKUP_PATH from Step 1; they never recompute a date-stamped path.
cd "$WORK/shared"
[ "$(git rev-parse --show-toplevel)" != "$PERSONAL" ] \
|| { echo "target IS sync.repo_path — ABORT, do not filter-repo"; exit 1; }
# The purge list derives from the COMPLETE set of sanitized paths — the same
# directories Phases 1-4 scanned. A filter list narrower than the scan
# (people/ + meetings/ only) leaves pre-sanitization history alive for every
# other scanned directory. The restore carrier below MUST match this same
# list — backed-up set, filtered set, and re-added set are identical.
PURGE_DIRS="people meetings daily companies projects analysis"
# Back up the clean working tree of every purged path to a DURABLE carrier
# (under $WORK in ~/.gbrain/backups — never /tmp, which can vanish mid-rewrite).
CLEAN="$WORK/clean"
mkdir -p "$CLEAN"
for d in $PURGE_DIRS; do
[ -d "$d" ] || continue
mkdir -p "$CLEAN/$d" && cp -r "$d/." "$CLEAN/$d/"
done
# Rewrite history: one --path per purged directory, derived from $PURGE_DIRS
rm -rf .git/filter-repo
git filter-repo --invert-paths $(for d in $PURGE_DIRS; do printf -- '--path %s/ ' "$d"; done) --force
# Restore clean files and re-commit as a single new commit — same $PURGE_DIRS
for d in $PURGE_DIRS; do
[ -d "$CLEAN/$d" ] || continue
mkdir -p "$d" && cp -r "$CLEAN/$d/." "$d/"
done
git remote add origin <SHARED_REPO_URL> # filter-repo removes remotes
for d in $PURGE_DIRS; do [ -d "$d" ] && git add "$d/"; done
git commit -m "Re-add sanitized directories"
# VERIFY RESTORE COMPLETENESS before the irreversible push — a partial restore
# would ship a smaller tree than was sanitized. Compare file counts (and, for
# extra safety, checksums) between the carrier and the restored tree.
before=$(find "$CLEAN" -type f | wc -l | tr -d ' ')
after=$(for d in $PURGE_DIRS; do [ -d "$d" ] && find "$d" -type f; done | wc -l | tr -d ' ')
[ "$before" = "$after" ] \
|| { echo "restore incomplete ($before → $after files) — ABORT, do not force-push"; exit 1; }
# Optional stronger check: diff -r "$CLEAN/<d>" "<d>" for each purged dir.
# RE-VERIFY the backup immediately before the irreversible step — card-time
# verification is not enough; time has passed and the rewrite could have gone
# sideways. Reuse $BACKUP_PATH (do NOT recompute $(date)); abort if unreadable.
git -C "$BACKUP_PATH" log -1 >/dev/null \
|| { echo "backup missing/unreadable — ABORT, do not force-push"; exit 1; }
git push --force origin main
Step 4 — log it (to the PERSONAL brain, NEVER the shared repo). Per
data-loss-gate, append the deletion under ## Data Deletions — but write it to
the PERSONAL brain's $PERSONAL/daily/notes/YYYY-MM-DD.md (or a local ops
log), never into the shared repo. The log names the purged paths AND the
backup location; in the shared repo those two facts would tell every team
member exactly which paths held sensitive content and where the
pre-sanitization backup lives — the audit trail becomes a treasure map.
Record: timestamp, purged paths, commit counts, and $BACKUP_PATH as the
recovery line.
After the force push:
gbrain sync errors or falls back to a full rescan, that is the cursor
recovering — run gbrain doctor if it doesn't settle~/.gbrain/backups/ for a retention window
(~30 days is a sane default), then delete it — it contains the
pre-sanitization history and should not accumulate indefinitely:
rm -rf ~/.gbrain/backups/shared-brain-history-backup-<date>.git
(the glob must match the shared-brain-history-backup-* name the backup
step created — a mismatched pattern deletes nothing and silently retains
the pre-sanitization history forever)Hand the repo to the team — stamp it shared first. Whichever path
produced the team repo (fresh-history export in Step 0 or the post-purge
force-push), stamp the published brain's audience before handoff:
gbrain config set brain.audience shared — run against the TEAM brain,
never the personal one. The stamp declares this a company/team brain, so
the ambient memory writeback consent nudge (a personal-brain ask) never
fires on it. If team members will run gbrain init for the shared brain
BEFORE this stamp exists (e.g. a fresh clone initializing its own engine),
have them prefix that one command with GBRAIN_NO_ONBOARD_NUDGE=1 — a
fresh un-stamped brain classifies personal, and the init-time nudge is
fire-once, so letting it fire there would both ask the wrong question and
burn the sentinel.
Sensitive data re-accumulates through meeting-transcript ingestion (candid assessments), enrichment pipelines pulling internal data, and manual writes during candid conversations. One clean pass is a snapshot, not a state.
Recommendation: schedule a monthly re-audit (weekly for high-ingest
brains) that re-runs Phases 1, 2, and 4 in report-only mode — scan and flag,
no edits — and surfaces new hits for human review before they reach the
shared repo. Wire it per
conventions/cron-via-minions.md: the
cron slot submits a background job (gbrain jobs submit), scheduling
guidance in skills/cron-scheduler/SKILL.md, job-lane routing in
skills/minion-orchestrator/SKILL.md. The report-only run writes its
findings summary; a human (or a gated follow-up run) does the removal.
gbrain check-backlinks check plus a grep for the removed section titles.This skill guarantees:
sync.repo_path — after (a) a mirror-clone backup exists and
is verified, and (b) a restore-completeness check passes before the
force-push. The personal brain's history is never rewritten.daily/) or a local ops
log, never into the shared repo.people/ alone.gbrain recall --grep, never merely expired — gbrain forget retains the row (struck through, served via --include-expired)
and can never certify clean.daily/notes/YYYY-MM-DD.md under
## Data Deletions with the backup path as the recovery line.brain.audience=shared at handoff and never
receives the ambient-writeback enablement nudge — that consent ask is
reserved for personal brains.writes_to: (edits in
place, plus the daily/ deletion log).The full behavior contract is documented in the body sections above; this section exists for the conformance test.
Three artifacts:
## Brainify Report — YYYY-MM-DD
- Scope: [N files scanned across people/, meetings/, daily/, ...]
- Flagged: [M files with hits] (triage list attached)
- Edited: [K files sanitized; T takes removed; F fact rows removed + re-synced + facts index reconciled]
- Verification: [grep residuals: 0 confirmed-sensitive; retrieval checks: clean]
- History: [not purged | fresh-export | purged after confirmed gate — backup at <path>]
- Next re-audit: [date / cron slot]
daily/notes/YYYY-MM-DD.md (never the shared repo) per
data-loss-gate Step 4.people/ — meetings, dailies, and cross-references leak
the same contentgbrain forget as sanitization — forget expires (struck-through
row retained, served via --include-expired); delete the fence row and
re-sync insteadpeople/ + meetings/git filter-repo / force-push without the mirror-clone backup
and the typed confirmation — the card comes BEFORE the rewrite, alwaysgit filter-repo / force-push in sync.repo_path — the purge
targets the SHARED repo cloned to a work dir; the personal brain's history is
never rewritten