business-context-os
LLM wiki kit
First committed by walm00
Published in walm00/business-context-os. Publisher page
22 GitHub stars
What it is
CLEAR Context OS is the maintenance layer your second brain never had: ownership boundaries enforced mechanically, staleness surfaced on a schedule, drift propagated across linked docs, a dispatcher that learns from your clicks. One source of truth per topic. Searchable. Task-aware.
AutoGineer overview, from the brain’s own files
CLEAR Context OS is a framework designed to solve the problem of silent context degradation in AI agents. By implementing a structured methodology called CLEAR (Contextual Ownership, Linking, Elimination, Alignment, Refinement), it provides a maintenance layer that manages knowledge through automated scheduling, ownership enforcement, and drift detection. It organizes information into specific zones—such as canonical data, wiki-based derivatives, and verbatim evidence—ensuring that agents always operate on the most accurate, source-of-truth-ranked information. The system includes a dispatcher for scheduled maintenance, a local dashboard for monitoring, and integration with Claude Code to facilitate onboarding and task-aware context retrieval.
How it works
Memory model: LLM wiki
AutoGineer overview, from the brain’s own files
The system organizes information into a folder hierarchy where the path itself acts as a trust signal for the LLM. It uses a dispatcher to run scheduled maintenance jobs that check for staleness, propagate updates across linked documents, and audit content health. New information is ingested through a routing process that places content into specific zones: canonical data for facts, wiki pages for operational knowledge, and collections for legal evidence. The system learns from user interactions to suggest fixes and uses frontmatter metadata to allow agents to filter and retrieve information efficiently without full-text scanning.
| Folder | Role | Files |
|---|---|---|
| .claude | agent-config | 193 |
| .github | agent-config | 6 |
| docs | docs | 68 |
The agent reads
- docs/_bcos-framework/guides/folder-conventions.md evidence: CLAUDE.md
- docs/_inbox/ evidence: README.md
The agent writes
- docs/_inbox/ evidence: CLAUDE.md
Requirements
Works with: Claude Code, OpenCode
Set it up
This brain runs code automatically: 5 hooks (claude-code), 1 script. Review .claude/settings.json, install.sh before opening the folder in Claude Code. No step below turns a hook on for you.
.claude/settings.json:bash "$CLAUDE_PROJECT_DIR/.claude/hooks/auto_save_session.sh".claude/settings.json:bash "$CLAUDE_PROJECT_DIR/.claude/hooks/precompact_save.sh".claude/settings.json:"$CLAUDE_PROJECT_DIR/.claude/bin/python3" "$CLAUDE_PROJECT_DIR/.claude/hooks/post_edit_frontmatter_check.py".claude/settings.json:"$CLAUDE_PROJECT_DIR/.claude/bin/python3" "$CLAUDE_PROJECT_DIR/.claude/hooks/post_edit_frontmatter_check.py".claude/settings.json:"$CLAUDE_PROJECT_DIR/.claude/bin/python3" "$CLAUDE_PROJECT_DIR/.claude/hooks/post_commit_context_check.py"install.sh:sh install.sh
Clone the repository at the commit AutoGineer scanned:
git clone https://github.com/walm00/business-context-os.git && cd business-context-os && git checkout 463568372f31f24fa6c01121c38f989845ca7c84Claude Code reads CLAUDE.md from this folder automatically.
cd business-context-os && claude
AutoGineer scanned these files at commit 4635683.
First committed by walm00. Published in walm00/business-context-os. Licence: MIT License.
Usage
AutoGineer overview, from the brain’s own files
- Automating the maintenance of project documentation and SOPs.
- Providing AI agents with a reliable, freshness-aware knowledge base.
- Managing ownership boundaries across large, multi-topic documentation sets.
- Syncing and auditing context across linked documents to prevent drift.
- Generating daily digests of system health and pending maintenance tasks.
- “Install BCOS from https://github.com/walm00/business-context-os and walk me through onboarding.”
- Claude clones the repository, sets up the environment, and guides the user through an interactive onboarding process to configure the context architecture.
- “/context bundle market-report:write”
- The agent retrieves a curated, freshness-aware package of context specifically relevant to writing a market report.
- “Run the audit twice a week.”
- The dispatcher updates the maintenance schedule to perform an audit of the knowledge base on a bi-weekly cadence.
- “/wiki run https://stripe.com/docs/api”
- The system fetches the URL, summarizes the content, and creates a cited wiki entry within the knowledge base.
Documentation by walm00
<p align="center"> <h1 align="center">CLEAR Context OS</h1> <p align="center"> <strong>Knowledge that maintains itself —</strong><br> so your AI doesn't act on what was true last month. </p> <p align="center"> <a href="#install">Install</a> · <a href="#what-it-does">What it does</a> · <a href="#the-wiki-zone">Wiki zone</a> · <a href="#what-ships">What ships</a> · <a href="docs/_bcos-framework/guides/getting-started.md">Getting Started</a> </p> <p align="center"> <img src="https://img.shields.io/badge/claude_code-ready-blueviolet" alt="Claude Code"> <img src="https://img.shields.io/badge/methodology-CLEAR-green" alt="CLEAR Methodology"> <img src="https://img.shields.io/badge/install-one_command-success" alt="One-command install"> <img src="https://img.shields.io/badge/skills-17-blue" alt="17 skills"> <img src="https://img.shields.io/badge/maintenance_jobs-12-orange" alt="12 maintenance jobs"> <img src="https://img.shields.io/badge/license-MIT-lightgrey" alt="MIT"> </p> </p>
Your AI had perfect context — two weeks ago. Then your strategy shifted, three meetings redefined priorities, and the docs you wrote on Monday are wrong by Friday. CLEAR Context OS is the maintenance layer your second brain never had: ownership boundaries enforced mechanically, staleness surfaced on a schedule, drift propagated across linked docs, a dispatcher that learns from your clicks. One source of truth per topic. Searchable. Task-aware. Never silently stale.
Install
Easiest — let Claude do it. Open Claude Code in any directory and paste:
"Install BCOS from https://github.com/walm00/business-context-os and walk me through onboarding."
Claude clones the repo, picks the right install path for your platform (Windows/macOS/Linux), runs setup, and steps straight into onboarding. No prereq checks to debug — if something's missing, Claude resolves it interactively.
Or manually, two commands:
curl -fsSL https://raw.githubusercontent.com/walm00/business-context-os/main/install.sh -o /tmp/bcos-install.sh
bash /tmp/bcos-install.sh(Requires bash, curl, and tar on PATH — fine on macOS/Linux and on Windows under WSL or Git Bash. Two steps instead of a single bash <(curl …) pipe so Claude Code's permission gate auto-approves both commands — you don't need to drop out to a terminal.)
Drop anything you already have — SOPs, brand docs, meeting notes, exports — into docs/_inbox/ (skip if you're starting fresh). Then open Claude Code in that repo and say:
"Launch BCOS onboarding."
That's the only prompt you need. Onboarding inspects your inbox, scans the rest of the repo, asks one Q&A round, and proposes the architecture for review. Works the same whether the repo is fresh or already full of context.
From zero to running
INSTALL → DISCOVER → ALIGN → SCHEDULE → RUNNING| # | Step | What happens |
|---|---|---|
| 1 | Install | One bash line drops the framework into any repo |
| 2 | Discover | Claude scans your repo + any MCP you've connected (Drive, Notion, Slack, Gmail, your CRM — whatever's wired in) for existing context, plus anything you've dropped into docs/_inbox/ |
| 3 | Align | One Q&A round — project type, key sources, ownership boundaries. Architecture drafted for your review |
| 4 | Schedule | Pick maintenance cadence in plain English: "audit twice a week", "dispatcher at 08:30", "deep daydream off" |
| 5 | Running | Daily digest. Local dashboard. /context bundle <task> ready. Context compounds from here — the system maintains itself. |
Simple, guided, automatic. Claude walks you through each step — you review, you decide. Nothing deleted along the way — originals preserved or archived, never silently overwritten.
What it does
Stops context rot in three ways:
| What it does | |
|---|---|
| Organize | Every doc declares what it owns. CLEAR boundaries prevent the same fact living in 5 places. |
| Maintain | Scheduled jobs check freshness, surface stale docs, propagate updates across linked content. |
| Use | /context search and /context bundle <task> give Claude curated, freshness-aware, source-of-truth-ranked context for the job at hand. |
The folder tells the LLM what to trust. Claude reads the path before the content: docs/*.md = canonical, _planned/ = not yet real, _archive/ = history, _inbox/ = unprocessed, _collections/ = verbatim evidence, _wiki/ = explanatory. The hierarchy is the trust signal — fewer tokens spent re-deciding, no chance of treating an archived draft as today's truth.
docs/
├── *.md ← canonical data points (one source of truth per topic)
├── document-index.md ← auto-generated TOC
├── current-state.md ← what's true right now + what changed recently
├── table-of-context.md ← high-level cluster map for orientation
├── _inbox/ ← drop zone — Claude triages on demand
├── _planned/ ← polished ideas, not yet real
├── _archive/ ← superseded — kept, not deleted
├── _collections/ ← verbatim evidence (invoices, contracts, transcripts)
│ └── <type>/_manifest.md (each collection has a manifest)
├── _wiki/ ← derivative knowledge (how-tos, source summaries)
│ ├── pages/ ← user-authored explainers
│ ├── source-summary/ ← external captures with citation banners
│ ├── raw/ ← original artifacts (PDFs, HTML)
│ └── queue.md ← URLs awaiting fetch
└── _bcos-framework/ ← framework docs — never user content
├── architecture/ ← 12 zone + system architecture docs
├── methodology/ ← 5 CLEAR + ownership + standards docs
├── patterns/ ← 8 project-type starting templates
└── templates/ ← 15 frontmatter / schema / starter filesThe wiki zone
Inspired by Karpathy's LLM Wiki approach — give the LLM a wiki of your knowledge, the way you'd brief a smart new hire.
Save anything to the wiki, from anywhere:
/wiki run https://stripe.com/docs/api ← fetch a URL, summarize, cite
/wiki create from /Users/me/Downloads/spec.pdf ← extract a PDF, link to the binary
/wiki promote docs/_inbox/meeting-notes.md ← turn an inbox capture into a wiki pageThe wiki holds how-tos, runbooks, glossaries, source summaries, post-mortems, decision logs — derivative knowledge that explains and supports your canonical data points. Every page cites what it builds on. Stale pages surface automatically when their sources advance.
Wiki content is searchable alongside the rest of your context:
/context search "stripe billing" ← cross-zone search, ranked by source-of-truth
/context bundle market-report:write ← curated bundle for a specific taskThe dashboard
A local cockpit at http://127.0.0.1:8091 that shows your system at a glance — no third-party services, no telemetry, no logins.
Image: BCOS dashboard cockpit — knowledge system status, things waiting on you, maintenance routine
python .claude/scripts/bcos-dashboard/run.py| Surface | What you see |
|---|---|
| Cockpit | One-line status (healthy / N waiting / heads-up). Per-job dot strip for every maintenance job (core BCOS + wiki zone). |
| Update | "Run full sync" button → update.py + CLAUDE.md drift review + auto-commit + push, with a live log drawer. |
Schedules (/settings/schedules) | Per-job preset buttons (daily, mon_wed_fri, weekly_mon, off) + the global auto-commit toggle + auto-fix whitelist. Saves directly to schedule-config.json. |
Run history (/settings/runs) | Last 20 dispatcher runs with filter chips (job / verdict / trigger). |
File health (/settings/files) | Frontmatter / cross-reference / staleness findings with one-click fixes. |
The dashboard is read-mostly: data flows from the dispatcher's diary, the schedule config, and the canonical context index. Writes (mark-done, schedule preset, auto-commit toggle, file fix) go through dedicated POST endpoints.
Requirements
Claude Code (desktop app, CLI, or web)
Python 3.8+ on
PATHbash (default macOS bash 3.2 is fine)
Updating
python .claude/scripts/update.pyRefreshes framework files only — skills, hooks, scripts, templates. Your docs/ and .private/ are never touched.
Maintenance
One scheduled task per repo. The dispatcher reads schedule-config.json, runs the jobs due today, writes one consolidated digest at docs/_inbox/daily-digest.md, and surfaces findings as one-click cards in the dashboard.
You can tune any of it in plain English:
"Run the audit twice a week." · "Move dispatcher to 08:30." · "Turn off deep daydream."
The system learns from your clicks. After three consistent uses of the same fix, the dashboard pre-selects it as a "✨ suggested" action — you accept or reject. Reversals trigger an automatic safety brake.
CLEAR — the methodology
Five principles, one rule each:
C — Contextual Ownership · one document owns each topic. No duplicates.
L — Linking · reference sources; don't copy them.
E — Elimination · consolidate; don't keep two versions.
A — Alignment · context that doesn't support decisions doesn't belong.
R — Refinement · structured maintenance, not ad-hoc fixes.
The whole framework is the mechanical implementation of these five rules.
What ships
Everything below installs as one repo drop-in. No third-party services, no logins, no telemetry — all state lives in your .claude/ and docs/ folders.
| Layer | Count | Examples |
|---|---|---|
| Skills (chat-invokable via slash command) | 17 | clear-planner · bcos-wiki · context-routing · context-audit · context-ingest · daydream · learning · schedule-tune · lessons-consolidate · ecosystem-manager |
| Sub-agents (delegated bounded tasks) | 3 | wiki-fetch · explore · plus one optional |
| Scripts (mechanical Python) | 46 | lifecycle_sweep · run_wiki_* (5) · cmd_wiki_* (7) · auto_fix_audit · bcos_inventory · digest_sidecar · record_resolution |
| Hooks (auto-validation on edit) | 4 | post-edit frontmatter check · post-commit context check · pre-compact save · auto-save session |
| Maintenance jobs (scheduled, one dispatcher) | 12 | index-health · audit-inbox · daydream-lessons · daydream-deep · architecture-review · auto-fix-audit · lifecycle-sweep · wiki-stale-propagation · wiki-source-refresh · wiki-graveyard · wiki-coverage-audit · wiki-canonical-drift |
| Auto-fix IDs (silent dispatcher fixes) | 12 | missing-last-updated · eof-newline · frontmatter-field-order · wiki-mark-queue-ingested · wiki-archive-expired-post-mortem |
| Architecture docs | 12 | wiki-zone.md · lifecycle-routing.md · typed-events.md · context-zones.md · content-routing.md · wiki-headless-scripts.md |
| Methodology docs | 5 | CLEAR principles · context architecture · decision framework · document standards · ownership specification |
| Project patterns (starting templates by project type) | 8 | client-project · gtm · marketing · operational · product-development · product-service · internal-tool-app · internal-tool-automation |
| Templates (frontmatter, schema, starters) | 15 | data-point · cluster · current-state · table-of-context · wiki-schema · wiki-config · session-diary-starter |
Every script and skill is documented at the source. Every job has a reference doc under .claude/skills/schedule-dispatcher/references/job-*.md. Every typed-event finding maps to a renderer in the dashboard cockpit. Adding a new check means dropping a cmd_*.py or run_*.py, registering it in one map, and the dashboard picks it up.
Contributing
Contributions welcome — open an issue or submit a PR targeting the dev branch. CI runs frontmatter, reference, and ecosystem-integration checks on every PR.
The fastest contribution path is lessons learned. As you use the system it captures insights; if you find one universal, contribute it back.
Origin
Built by Guntis Coders after two years of operating context systems in production. The CLEAR methodology emerged from a practical problem: AI context degrades silently, and no amount of one-time documentation prevents it. The solution required a system — ownership boundaries, automated maintenance, self-learning, and structured reflection.
Background: What is the Table of Contexts and why does it matter.
License
.claude/scripts/update.py
Shown as plain text.
#!/usr/bin/env python3
"""
CLEAR Context OS — Update Script
Downloads the latest framework files from upstream and applies them to your
local installation. Your business context (docs/, .private/) is never touched.
Usage:
python .claude/scripts/update.py # Interactive update
python .claude/scripts/update.py --dry-run # Preview changes only
python .claude/scripts/update.py --yes # Apply without confirmation prompt
python .claude/scripts/update.py --upstream your-org/business-context-os
python .claude/scripts/update.py --branch main
python .claude/scripts/update.py --local /path/to/upstream-clone
"""
import os
import sys
import shutil
import hashlib
import tempfile
import zipfile
import difflib
import argparse
import datetime
import ssl
import urllib.request
import urllib.error
from pathlib import Path
# ---------------------------------------------------------------------------
# Pause guard
# ---------------------------------------------------------------------------
# A repo pauses BCOS framework updates by creating `.bcos-update-paused` at
# its root. The file's contents (if any) are surfaced as the pause reason.
# Use cases: framework-source repo (outbound publish only), mid-migration
# pins, custom-tuned installs, vacation holds.
#
# The pause sentinel itself is per-install state and never ships from the
# source repo (publish.sh's DEV_ONLY_PATHS strips it), so downstream installs
# only see this file if they create it themselves.
#
# Toggle via Command Center per-row Pause/Resume button, or by hand:
# touch .bcos-update-paused # pause
# rm .bcos-update-paused # resume
_SENTINEL = Path(__file__).resolve().parents[2] / ".bcos-update-paused"
if _SENTINEL.is_file():
try:
reason = _SENTINEL.read_text(encoding="utf-8").strip()
except OSError:
reason = ""
print("ERROR: BCOS updates paused for this repo.", file=sys.stderr)
print(f"Reason: {reason or '(no reason given)'}", file=sys.stderr)
print(f"Resume by deleting {_SENTINEL.name} at the repo root.", file=sys.stderr)
sys.exit(2)
# ---------------------------------------------------------------------------
# Configuration — update UPSTREAM_REPO before public launch
# ---------------------------------------------------------------------------
UPSTREAM_REPO = "walm00/business-context-os"
UPSTREAM_BRANCH = "main"
# Framework directories — synced from upstream on every update.
# Anything NOT listed here is user content and is never touched.
FRAMEWORK_DIRS = [
".claude/agents",
".claude/hooks",
".claude/scripts",
".claude/skills",
".claude/templates",
"docs/_bcos-framework/architecture",
"docs/_bcos-framework/guides",
"docs/_bcos-framework/methodology",
"docs/_bcos-framework/patterns",
"docs/_bcos-framework/templates",
"examples",
]
# Framework files synced from upstream on every update (always overwritten).
# These are NOT user content — they live outside FRAMEWORK_DIRS for structural
# reasons but are owned by the framework.
FRAMEWORK_FILES = [
".claude/quality/schedule-config.template.json",
".claude/quality/lifecycle-routing.yml",
".claude/quality/ecosystem/config.json",
".claude/quality/ecosystem/lessons-schema.md",
".claude/ECOSYSTEM-MAP.md",
]
# Plugin-owned overlay paths — explicitly NOT framework-managed. Listed here
# only as documentation so future maintainers don't accidentally add them to
# FRAMEWORK_DIRS or FRAMEWORK_FILES. update.py does not touch these:
#
# docs/_wiki/.schema.yml — per-install live schema, user-owned
# docs/_wiki/.schema.d/ — plugin schema fragments (one file per plugin)
# written by each plugin's install_here.py
# see docs/_bcos-framework/architecture/
# wiki-zone.md "Schema fragments overlay"
# docs/_<plugin>/ — plugin-owned data zone (custom-optout)
#
# These survive every BCOS update. The merger that combines base schema +
# fragments lives at .claude/scripts/_wiki_schema_merge.py.
# Files that are auto-merged on update.
#
# `.gitignore` USED to live here. It now does not: `.gitignore` is a rendered
# artifact owned by `set_profile.sh` / `bcos_profile.set_profile()`, rendered
# from `.claude/templates/gitignore.template` (which IS framework-synced via
# FRAMEWORK_DIRS). After every update we re-render `.gitignore` from the
# freshly-synced template using the repo's current profile — so personal-
# profile repos don't get SHARED-only patterns re-introduced on every sync.
# See `_refresh_gitignore_from_profile()` in this file.
MERGE_FILES: list[str] = []
# CLAUDE.md — user is shown a diff and chooses what to do
REVIEW_FILES = [
"CLAUDE.md",
]
# ---------------------------------------------------------------------------
# Utilities
# ---------------------------------------------------------------------------
def file_hash(path: str) -> str:
"""Hash file contents, normalizing line endings so CRLF == LF."""
h = hashlib.sha256()
with open(path, "rb") as f:
h.update(f.read().replace(b"\r\n", b"\n"))
return h.hexdigest()
def posix(path) -> str:
"""Normalize a path to forward-slash form for reliable comparison."""
return Path(path).as_posix()
def download_upstream(repo: str, branch: str, dest_dir: str) -> str:
"""Download and extract the upstream zip. Returns path to extracted root."""
url = f"https://github.com/{repo}/archive/refs/heads/{branch}.zip"
print(f" Fetching {url} ...")
zip_path = os.path.join(dest_dir, "upstream.zip")
try:
urllib.request.urlretrieve(url, zip_path)
except (ssl.SSLError, urllib.error.URLError) as e:
# macOS python.org installers ship without cert bundle configuration, which
# surfaces here as an SSL verification failure. Give a targeted hint.
err = str(e)
is_ssl = isinstance(e, ssl.SSLError) or "SSL" in err or "certificate" in err.lower()
print(f"\nERROR: Could not download upstream: {e}")
if is_ssl and sys.platform == "darwin":
print("")
print("SSL certificate verification failed. If you installed Python")
print("from python.org, run the certificate installer once:")
print("")
print(" /Applications/Python\\ 3.*/Install\\ Certificates.command")
print("")
print("Or install Python via Homebrew (`brew install python`), which")
print("ships with certs pre-wired.")
else:
print("Check your internet connection and the upstream repo URL.")
sys.exit(1)
except Exception as e:
print(f"\nERROR: Could not download upstream: {e}")
print("Check your internet connection and the upstream repo URL.")
sys.exit(1)
with zipfile.ZipFile(zip_path, "r") as z:
z.extractall(dest_dir)
repo_name = repo.split("/")[-1]
extracted = os.path.join(dest_dir, f"{repo_name}-{branch}")
if not os.path.isdir(extracted):
print(f"\nERROR: Expected extracted directory at {extracted}")
sys.exit(1)
return extracted
def collect_framework_files(root: str) -> list[str]:
"""Return all framework file paths relative to root (posix form).
Skips Python bytecode caches (__pycache__ dirs and *.pyc files) — those are
machine-local artifacts that should never sync between installs."""
files = []
for d in FRAMEWORK_DIRS:
dir_path = os.path.join(root, d)
if not os.path.isdir(dir_path):
continue
for dirpath, dirnames, filenames in os.walk(dir_path):
# Prune __pycache__ before descending (modifies dirnames in-place)
dirnames[:] = [dn for dn in dirnames if dn != "__pycache__"]
for fname in filenames:
if fname.endswith(".pyc"):
continue
full = os.path.join(dirpath, fname)
rel = posix(os.path.relpath(full, root))
files.append(rel)
for f in FRAMEWORK_FILES + MERGE_FILES + REVIEW_FILES:
if os.path.isfile(os.path.join(root, f)):
files.append(posix(f))
return files
def classify(upstream_path: str, local_path: str) -> str:
"""Return 'new', 'modified', or 'unchanged'."""
if not os.path.exists(local_path):
return "new"
if file_hash(upstream_path) != file_hash(local_path):
return "modified"
return "unchanged"
def print_diff(upstream_path: str, local_path: str, rel: str, max_lines: int = 60):
with open(local_path, "r", encoding="utf-8", errors="replace") as f:
local_lines = f.readlines()
with open(upstream_path, "r", encoding="utf-8", errors="replace") as f:
up_lines = f.readlines()
diff = list(difflib.unified_diff(
local_lines, up_lines,
fromfile=f"local/{rel}",
tofile=f"upstream/{rel}",
lineterm="",
))
if not diff:
print(" (files differ by metadata only)")
return
for line in diff[:max_lines]:
print(f" {line}")
if len(diff) > max_lines:
print(f" ... ({len(diff) - max_lines} more lines — save as .upstream to review in full)")
def _refresh_gitignore_from_profile(local_root: Path) -> None:
"""Re-render `.gitignore` from the freshly-synced template + current profile.
The framework owns `.claude/templates/gitignore.template` (synced via
FRAMEWORK_DIRS). The repo's profile (`.claude/bcos-profile`, default
`shared`) selects which sections of the template land in `.gitignore`.
This is the same renderer the dashboard + `set_profile.sh` use — we
just invoke it post-update so SHARED-only patterns aren't re-introduced
on personal-profile repos every time someone runs `update.py`.
Non-fatal: any error logs a hint and returns. Update.py should never
abort over a polish step.
"""
# `bcos_profile.py` lives under `.claude/scripts/bcos-dashboard/` and
# imports its own `single_repo` from the same folder, so we have to put
# that directory on sys.path before importing.
dashboard_dir = local_root / ".claude" / "scripts" / "bcos-dashboard"
if not (dashboard_dir / "bcos_profile.py").is_file():
print(f" .gitignore: skipped re-render (bcos_profile.py not found — old install?).")
return
template_path = local_root / ".claude" / "templates" / "gitignore.template"
if not template_path.is_file():
print(f" .gitignore: skipped re-render (template not synced — check FRAMEWORK_DIRS).")
return
if str(dashboard_dir) not in sys.path:
sys.path.insert(0, str(dashboard_dir))
try:
# Reimport defensively in case an older version was cached earlier
# in this same process (the dashboard ships the module; the loader
# may have picked up the previous version before sync).
import importlib
try:
import bcos_profile # type: ignore[import-not-found]
importlib.reload(bcos_profile)
except Exception:
import bcos_profile # type: ignore[import-not-found]
current = bcos_profile.read_profile()
result = bcos_profile.set_profile(current)
except Exception as exc: # noqa: BLE001
print(f" .gitignore: re-render failed ({type(exc).__name__}: {exc}, non-fatal).")
return
if not result.get("ok"):
err = result.get("error", "unknown error")
print(f" .gitignore: re-render failed: {err} (non-fatal).")
return
if result.get("gitignore_changed"):
print(f" .gitignore: re-rendered from template (profile: {current}).")
else:
print(f" .gitignore: already current for profile '{current}'.")
def merge_reference_index(upstream_path: str, local_path: str) -> int:
"""Merge upstream reference-index entries into local. Additive only.
Preserves user-added custom references; never removes any local entries.
Returns total count of entries added across all categories.
"""
import json as _json
if not os.path.exists(upstream_path):
return 0
with open(upstream_path, "r", encoding="utf-8") as f:
upstream = _json.load(f)
if not os.path.exists(local_path):
os.makedirs(os.path.dirname(local_path), exist_ok=True)
shutil.copy2(upstream_path, local_path)
total = 0
for category in upstream.get("references", {}).values():
if isinstance(category, dict):
total += len(category)
return total
with open(local_path, "r", encoding="utf-8") as f:
local = _json.load(f)
added = 0
up_refs = upstream.get("references", {})
lc_refs = local.setdefault("references", {})
for category, entries in up_refs.items():
if not isinstance(entries, dict):
continue
lc_cat = lc_refs.setdefault(category, {})
for key, path in entries.items():
if key not in lc_cat:
lc_cat[key] = path
added += 1
if added > 0:
local["lastUpdated"] = datetime.date.today().isoformat()
with open(local_path, "w", encoding="utf-8") as f:
_json.dump(local, f, indent=2)
f.write("\n")
return added
def merge_entities(upstream_path: str, local_path: str) -> int:
"""Merge upstream entities.json categories into local. Additive only.
Preserves user-added entities; never removes any local entries.
Dedupes by `canonical` (for objects with that field) or by `term` (for
glossary entries). Returns total count of entries added across categories.
"""
import json as _json
if not os.path.exists(upstream_path):
return 0
with open(upstream_path, "r", encoding="utf-8") as f:
upstream = _json.load(f)
if not os.path.exists(local_path):
os.makedirs(os.path.dirname(local_path), exist_ok=True)
shutil.copy2(upstream_path, local_path)
total = 0
for category in upstream.get("entities", {}).values():
if isinstance(category, list):
total += len(category)
return total
with open(local_path, "r", encoding="utf-8") as f:
local = _json.load(f)
added = 0
up_ents = upstream.get("entities", {})
lc_ents = local.setdefault("entities", {})
for category, entries in up_ents.items():
if not isinstance(entries, list):
continue
lc_list = lc_ents.setdefault(category, [])
existing_keys = set()
for e in lc_list:
if isinstance(e, dict):
key = e.get("canonical") or e.get("term")
if key:
existing_keys.add(key)
for e in entries:
if not isinstance(e, dict):
continue
key = e.get("canonical") or e.get("term")
if key and key not in existing_keys:
lc_list.append(e)
existing_keys.add(key)
added += 1
if added > 0:
local["lastUpdated"] = datetime.date.today().isoformat()
with open(local_path, "w", encoding="utf-8") as f:
_json.dump(local, f, indent=2)
f.write("\n")
return added
# merge_settings_json now lives in `_settings_merge.py` so tests + tooling
# can import it without triggering update.py's pause-sentinel guard.
# Re-exported here for backwards compatibility with any external caller.
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from _settings_merge import merge_settings_json # noqa: E402,F401
def merge_schedule_config(template_path: str, live_path: str, *,
interactive: bool = True) -> int:
"""Merge template-only jobs into the live schedule-config.json.
The framework ships new jobs (lifecycle-sweep, wiki-canonical-drift, etc.)
in schedule-config.template.json. update.py overwrites the template on
every sync, but the LIVE config (schedule-config.json) carries user
customizations and is never touched. Without this helper, new template
jobs silently never propagate to existing installs.
Strategy (Option A — manual prompt):
1. Find jobs in template that don't exist in live config.
2. List them with their default cadence + _about description.
3. Prompt user (Y/n) — default Yes.
4. If yes, copy template entries verbatim into live config. User
customizations on EXISTING jobs are preserved (we never touch
shared keys).
Non-interactive mode (--yes) auto-adds without prompting.
Returns the number of jobs added.
"""
import json as _json
if not (os.path.exists(template_path) and os.path.exists(live_path)):
return 0
try:
with open(template_path, "r", encoding="utf-8") as f:
template = _json.load(f)
with open(live_path, "r", encoding="utf-8") as f:
live = _json.load(f)
except (_json.JSONDecodeError, OSError) as exc:
print(f" schedule-config.json: skipped (parse error: {exc})")
return 0
template_jobs = template.get("jobs") or {}
live_jobs = live.get("jobs") or {}
if not isinstance(template_jobs, dict) or not isinstance(live_jobs, dict):
return 0
new_job_ids = [jid for jid in template_jobs if jid not in live_jobs]
if not new_job_ids:
return 0
print(f" schedule-config.json: {len(new_job_ids)} new job(s) available in template:")
for jid in new_job_ids:
spec = template_jobs[jid] or {}
about = (spec.get("_about") or "").strip()
sched = spec.get("schedule", "?")
print(f" + {jid:26} (default cadence: {sched})")
if about:
short = about[:96] + ("…" if len(about) > 96 else "")
print(f" {short}")
if interactive:
resp = input(f" Add these {len(new_job_ids)} job(s) to your live schedule? [Y/n] ").strip().lower()
if resp in ("n", "no"):
print(f" schedule-config.json: skipped — run /schedule-tune later to add new jobs.")
return 0
else:
print(f" schedule-config.json: --yes mode, auto-adding…")
for jid in new_job_ids:
live_jobs[jid] = template_jobs[jid]
live["jobs"] = live_jobs
# Also merge any new auto_fix.whitelist entries that ship in the template
# but aren't on the live config — same additive principle.
template_whitelist = ((template.get("auto_fix") or {}).get("whitelist") or [])
live_whitelist = ((live.get("auto_fix") or {}).get("whitelist") or [])
if template_whitelist and live_whitelist is not None:
new_fixes = [w for w in template_whitelist if w not in live_whitelist]
if new_fixes:
print(f" schedule-config.json: also adding {len(new_fixes)} new auto-fix ID(s) to whitelist: {', '.join(new_fixes)}")
live.setdefault("auto_fix", {}).setdefault("whitelist", []).extend(new_fixes)
with open(live_path, "w", encoding="utf-8") as f:
_json.dump(live, f, indent=2)
f.write("\n")
return len(new_job_ids)
def ensure_python_shim(project_root: str) -> list:
"""Create .claude/bin/python3 (POSIX) and .claude/bin/python3.cmd (Windows)
shims if missing or stale. Returns list of what was created/refreshed.
Why: Windows `python3` resolves to the Microsoft Store stub which exits 49
without running. Hooks, settings.json hook commands, and scheduled-task
Bash invocations that hardcoded `python3` all failed silently. The shim
bypasses the stub by using `py -3` (Windows Python Launcher). POSIX shim
is a passthrough so callers never branch on OS.
"""
created = []
bin_dir = os.path.join(project_root, ".claude", "bin")
os.makedirs(bin_dir, exist_ok=True)
# Windows shim
win_shim_path = os.path.join(bin_dir, "python3.cmd")
win_shim_content = (
"@echo off\r\n"
"py -3 %*\r\n"
"exit /b %ERRORLEVEL%\r\n"
)
win_existing = ""
if os.path.exists(win_shim_path):
try:
with open(win_shim_path, "rb") as f:
win_existing = f.read().decode("utf-8", errors="replace")
except Exception:
win_existing = ""
if win_existing.strip() != win_shim_content.strip():
with open(win_shim_path, "wb") as f:
f.write(win_shim_content.encode("utf-8"))
created.append(" ~ .claude/bin/python3.cmd")
# POSIX shim — also handles Windows Git Bash by preferring `py -3` if
# available (Python Launcher is never aliased to the MS Store stub).
# On macOS/Linux, `py` doesn't exist and we fall through to env python3.
posix_shim_path = os.path.join(bin_dir, "python3")
posix_shim_content = (
"#!/usr/bin/env bash\n"
"# BCOS Python shim - passthrough. Generated by install.sh / update.py.\n"
"# Do not edit; regenerate via `bash install.sh` or `.claude/bin/python3 .claude/scripts/update.py`.\n"
"if command -v py > /dev/null 2>&1; then\n"
' exec py -3 "$@"\n'
"fi\n"
'exec /usr/bin/env python3 "$@"\n'
)
posix_existing = ""
if os.path.exists(posix_shim_path):
try:
with open(posix_shim_path, "r", encoding="utf-8") as f:
posix_existing = f.read()
except Exception:
posix_existing = ""
if posix_existing.strip() != posix_shim_content.strip():
with open(posix_shim_path, "w", encoding="utf-8", newline="\n") as f:
f.write(posix_shim_content)
try:
os.chmod(posix_shim_path, 0o755)
except Exception:
pass # Windows filesystems ignore chmod; fine
created.append(" ~ .claude/bin/python3")
return created
def ensure_convention_infrastructure(project_root: str, upstream_root: str) -> list:
"""Create convention directories and files that hooks/scripts depend on.
Returns list of what was created."""
created = []
# Directories that must exist
convention_dirs = [
"docs/_inbox/sessions",
"docs/_collections",
".claude/hook_state",
".private",
]
for d in convention_dirs:
full = os.path.join(project_root, d)
if not os.path.isdir(full):
os.makedirs(full, exist_ok=True)
created.append(f" + {d}/")
# Private starter templates (copy if missing, never overwrite)
private_starter_dir = os.path.join(upstream_root, "docs", "_bcos-framework", "templates", "private-starter")
if os.path.isdir(private_starter_dir):
for fname in os.listdir(private_starter_dir):
if not fname.endswith(".md"):
continue
src = os.path.join(private_starter_dir, fname)
dst = os.path.join(project_root, ".private", fname)
if not os.path.exists(dst):
shutil.copy2(src, dst)
created.append(f" + .private/{fname}")
# Gitkeep files (claude state + empty wiki subdirs so structure survives clone)
for d in [
".claude/hook_state",
"docs/_wiki/pages",
"docs/_wiki/source-summary",
"docs/_wiki/.archive",
"docs/_wiki/.schema.d",
]:
full = os.path.join(project_root, d)
if os.path.isdir(full):
gitkeep = os.path.join(full, ".gitkeep")
if not os.path.exists(gitkeep):
Path(gitkeep).touch()
# Wiki zone — MUST exist (plugin-storage-contract.md Rule 2). Idempotent;
# no-op if zone already initialized. Catches pre-wiki installs upgrading
# into the wiki-enabled framework.
ensure_wiki_script = os.path.join(project_root, ".claude", "scripts", "ensure_wiki_zone.py")
if os.path.exists(ensure_wiki_script):
try:
import subprocess, json as _json
res = subprocess.run(
[sys.executable, ensure_wiki_script],
cwd=project_root, capture_output=True, text=True, timeout=20,
)
try:
payload = _json.loads(res.stdout) if res.stdout else {}
except Exception:
payload = {}
if payload.get("ok") and not payload.get("no_op"):
for p in payload.get("created", [])[:6]:
created.append(f" + {p}")
elif not payload.get("ok"):
created.append(f" ! wiki zone: {payload.get('notes', 'init failed')}")
except Exception as e:
created.append(f" ! wiki zone: ensure skipped ({e.__class__.__name__})")
return created
# ---------------------------------------------------------------------------
# README check
# ---------------------------------------------------------------------------
def check_readme(project_root: Path, dry_run: bool) -> None:
"""If no README.md exists and BCOS content is present, create a minimal one.
Three cases:
- README exists → skip (never touch an existing README, even if empty).
- README missing + no BCOS content yet → note it for later; too early.
- README missing + BCOS content present → create a minimal repo README.
"""
readme_path = project_root / "README.md"
if readme_path.exists():
return # existing repo — never touch it
# Detect whether meaningful BCOS content has been built up yet.
# We look for any active context file (not just framework scaffolding).
has_content = any([
(project_root / "docs" / "table-of-context.md").is_file(),
(project_root / "docs" / "current-state.md").is_file(),
(project_root / "docs" / "document-index.md").is_file(),
])
if not has_content:
print(" README.md: not found — no content yet, will create once context is established.")
return
if dry_run:
print(" README.md: would create (no README found, BCOS content present)")
return
repo_name = project_root.name
# Produce a human-readable title from the repo/folder name
title = repo_name.replace("-", " ").replace("_", " ").title()
readme_content = f"""# {title}
This repository uses [CLEAR Context OS](https://github.com/walm00/business-context-os)
to maintain structured business context for AI-assisted work.
## Navigation
| Location | Contents |
|----------|---------|
| `docs/` | Active context — current business reality |
| `docs/_inbox/` | Raw material waiting to be processed |
| `docs/_planned/` | Ideas and drafts — not yet active |
| `docs/_archive/` | Historical — superseded documents |
| `.private/` | Local-only context — never committed |
## Using with Claude Code
Open Claude Code in this directory and start working. Claude reads the context
automatically and uses it to give you accurate, up-to-date assistance.
To update the framework:
```bash
python .claude/scripts/update.py
```
"""
readme_path.write_text(readme_content, encoding="utf-8")
print(" README.md: created (minimal BCOS context README).")
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
def main():
parser = argparse.ArgumentParser(
description="Update CLEAR Context OS framework files from upstream."
)
parser.add_argument("--dry-run", action="store_true",
help="Preview what would change; apply nothing")
parser.add_argument("--yes", "-y", action="store_true",
help="Apply framework updates without a confirmation prompt")
parser.add_argument("--upstream", default=None,
help=f"Upstream GitHub repo (default: {UPSTREAM_REPO})")
parser.add_argument("--branch", default=UPSTREAM_BRANCH,
help=f"Upstream branch (default: {UPSTREAM_BRANCH})")
parser.add_argument("--local", default=None, metavar="PATH",
help="Use a local directory as upstream instead of downloading from GitHub")
args = parser.parse_args()
local_root = Path(__file__).resolve().parent.parent.parent # repo root
print()
print("=" * 62)
print(" CLEAR Context OS — Update")
print("=" * 62)
print(f" Local: {local_root}")
if args.local:
print(f" Upstream: {args.local} (local path)")
else:
upstream_repo = args.upstream or UPSTREAM_REPO
print(f" Upstream: github.com/{upstream_repo} (branch: {args.branch})")
if args.dry_run:
print(" Mode: DRY RUN — no changes will be made")
print()
# ------------------------------------------------------------------ scan
def run_scan(upstream_root: str):
framework_files = collect_framework_files(upstream_root)
review_set = set(posix(f) for f in REVIEW_FILES)
merge_set = set(posix(f) for f in MERGE_FILES)
new_files = [] # (rel, upstream_path, local_path)
modified_files = []
review_files = [] # files needing user decision
merge_files = [] # files to auto-merge
unchanged = 0
for rel in framework_files:
upstream_path = os.path.join(upstream_root, rel)
local_path = str(local_root / rel)
status = classify(upstream_path, local_path)
if rel in review_set:
if status != "unchanged":
review_files.append((rel, upstream_path, local_path, status))
else:
unchanged += 1
elif rel in merge_set:
if status != "unchanged":
merge_files.append((rel, upstream_path, local_path, status))
else:
unchanged += 1
elif status == "new":
new_files.append((rel, upstream_path, local_path))
elif status == "modified":
modified_files.append((rel, upstream_path, local_path))
else:
unchanged += 1
# ------------------------------------------------------------ report
total = len(new_files) + len(modified_files)
print(f" Scan complete:")
print(f" {len(new_files):3d} new framework files")
print(f" {len(modified_files):3d} modified framework files")
print(f" {len(review_files):3d} require your review (CLAUDE.md)")
print(f" {unchanged:3d} already up to date")
print()
if total == 0 and not review_files and not merge_files:
# Even with no framework-file drift, the Python shim may be
# missing — happens on every repo installed before the shim
# feature shipped. Run shim convergence unconditionally so
# existing installs heal on the next update run.
shim_created = ensure_python_shim(str(local_root))
if shim_created:
print(" Python shim:")
for item in shim_created:
print(item)
print()
print(" Already up to date. Nothing to do.")
print()
return
if new_files:
print(" NEW:")
for rel, _, _ in new_files:
print(f" + {rel}")
print()
if modified_files:
print(" MODIFIED:")
for rel, _, _ in modified_files:
print(f" ~ {rel}")
print()
if args.dry_run:
print(" Dry run complete. Run without --dry-run to apply.")
print()
return
# ---------------------------------------------------- confirm + apply
if not args.yes and total > 0:
resp = input(f" Apply {total} framework file update(s)? [y/N] ").strip().lower()
if resp != "y":
print(" Cancelled.")
return
print()
applied = 0
for rel, upstream_path, local_path in new_files + modified_files:
os.makedirs(os.path.dirname(local_path), exist_ok=True)
shutil.copy2(upstream_path, local_path)
applied += 1
if applied:
print(f" Applied {applied} file(s).")
# --------- self-relaunch if update.py itself was updated
self_updated = any(
rel == ".claude/scripts/update.py"
for rel, _, _ in new_files + modified_files
)
if self_updated:
print()
print(" Update script itself was updated. Re-launching new version...")
print()
import subprocess as _sp
new_args = [sys.executable, str(local_root / ".claude" / "scripts" / "update.py"), "--yes"]
if args.local:
new_args.extend(["--local", args.local])
result = _sp.run(new_args, cwd=str(local_root))
sys.exit(result.returncode)
# subprocess runs the new version — we exit after it finishes
# ----------------------------------- re-render .gitignore from template
# Profile-aware. `.gitignore` is not merged from upstream — it is a
# rendered output of `.claude/templates/gitignore.template` + the
# repo's current profile (`shared` / `personal`). The template was
# just synced as part of FRAMEWORK_DIRS above; now we re-render so
# personal-profile repos don't get SHARED-only patterns re-added.
_refresh_gitignore_from_profile(local_root)
# ------------------------------------------------ merge settings.json
upstream_settings = os.path.join(upstream_root, ".claude", "settings.json")
local_settings = str(local_root / ".claude" / "settings.json")
if os.path.exists(upstream_settings):
entries_added = merge_settings_json(upstream_settings, local_settings)
if entries_added:
print(f" settings.json: merged {entries_added} new entries (hooks + permissions) from upstream.")
else:
print(f" settings.json: all upstream entries already registered.")
# ------ Permissions catalog drift check (advisory) ----------
# Surfaces drift between catalog SoT and shipped settings.
# Advisory: prints a warning but never fails the update.
# See docs/_bcos-framework/architecture/permissions-write-contract.md
try:
import subprocess as _sp
_validator = str(local_root / ".claude" / "scripts" / "validate_permissions_catalog.py")
if os.path.isfile(_validator):
_res = _sp.run(
[sys.executable, _validator, "--quiet"],
cwd=str(local_root), capture_output=True, text=True, timeout=15,
)
if _res.returncode != 0 and _res.stdout.strip():
print()
print(f" {_res.stdout.strip()}")
print(f" Detail: python .claude/scripts/validate_permissions_catalog.py")
except Exception:
pass # never abort update on advisory check failure
# ----------------------------------- merge schedule-config.json
# The template just got updated above (it's in FRAMEWORK_FILES). Now
# surface any template-only jobs to the user's live config so the
# dispatcher actually picks them up. User customizations on existing
# jobs are preserved — we only append new entries.
upstream_template = os.path.join(
upstream_root, ".claude", "quality", "schedule-config.template.json"
)
local_schedule = str(local_root / ".claude" / "quality" / "schedule-config.json")
if os.path.exists(upstream_template) and os.path.exists(local_schedule):
jobs_added = merge_schedule_config(
upstream_template, local_schedule, interactive=not args.yes,
)
if jobs_added:
print(f" schedule-config.json: added {jobs_added} new job(s) from template.")
# ------------------------------------------------ refresh ecosystem state.json
# state.json is a derived artifact — regenerated from disk every update.
# See lesson L-INIT-20260404-009: discovery is the source of truth, state
# files record what discovery found. The previous additive-merge model was
# disk-blind and caused systemic drift across deployed repos.
refresh_script = str(local_root / ".claude" / "scripts" / "refresh_ecosystem_state.py")
if os.path.exists(refresh_script):
try:
import subprocess as _sp
result = _sp.run(
[sys.executable, refresh_script],
cwd=str(local_root),
capture_output=True, text=True, timeout=30,
)
summary = result.stdout.strip().splitlines()[-1] if result.stdout.strip() else ""
if result.returncode == 0 and summary:
print(f" {summary}")
elif result.returncode != 0:
print(f" state.json: refresh exited {result.returncode} (non-fatal)")
except Exception as e:
print(f" state.json: could not refresh ({e}, non-fatal)")
# ------------------------------------------------ merge reference-index.json
# Same additive pattern. Framework references stay current; user custom
# references are preserved.
upstream_ref = os.path.join(upstream_root, ".claude", "registries", "reference-index.json")
local_ref = str(local_root / ".claude" / "registries" / "reference-index.json")
if os.path.exists(upstream_ref):
ref_added = merge_reference_index(upstream_ref, local_ref)
if ref_added:
print(f" reference-index.json: added {ref_added} new entry/entries from upstream.")
else:
print(f" reference-index.json: all upstream entries already present.")
# ------------------------------------------------ merge entities.json
# Same additive pattern. Framework-shipped canonical entities stay
# current; user-added people/projects/terms are preserved.
upstream_ent = os.path.join(upstream_root, ".claude", "registries", "entities.json")
local_ent = str(local_root / ".claude" / "registries" / "entities.json")
if os.path.exists(upstream_ent):
ent_added = merge_entities(upstream_ent, local_ent)
if ent_added:
print(f" entities.json: added {ent_added} new entry/entries from upstream.")
else:
print(f" entities.json: all upstream entries already present.")
# ----------------------------------------- Python shim (Win/macOS fix)
# Ensures .claude/bin/python3 + .claude/bin/python3.cmd exist so
# BCOS-controlled callers (hooks, settings.json hook commands, codex
# hooks) can invoke Python via the shim instead of bare `python3`.
# On Windows this bypasses the MS Store stub; on POSIX it's a
# transparent passthrough. Idempotent.
shim_created = ensure_python_shim(str(local_root))
if shim_created:
print(f" Python shim:")
for item in shim_created:
print(item)
# ----------------------------------------- convention infrastructure
infra_created = ensure_convention_infrastructure(str(local_root), upstream_root)
if infra_created:
print(f" Convention infrastructure:")
for item in infra_created:
print(item)
# ------------------------------------------------------ README check
check_readme(local_root, args.dry_run)
# ----------------------------------------- regenerate wake-up context
wakeup_script = str(local_root / ".claude" / "scripts" / "generate_wakeup_context.py")
toc_exists = (local_root / "docs" / "table-of-context.md").is_file()
cs_exists = (local_root / "docs" / "current-state.md").is_file()
if os.path.exists(wakeup_script) and (toc_exists or cs_exists):
try:
import subprocess
subprocess.run([sys.executable, wakeup_script], cwd=str(local_root),
capture_output=True, timeout=15)
print(f" Wake-up context regenerated.")
except Exception:
print(f" Wake-up context: could not regenerate (non-critical).")
# ---------------------------------------------------- CLAUDE.md (boundary-aware)
# The shipped CLAUDE.md wraps the framework-managed portion in
# <!-- BCOS:CORE:START vX.Y.Z --> ... <!-- BCOS:CORE:END --> markers.
# ensure_bcos_core_block refreshes ONLY that block; everything outside
# the markers (user identity, plugin notes, team conventions) is
# untouched. If the previous CORE differed from the new one, it is
# saved to .claude/bcos-claude-reference.md so the user can recover
# any unintended hand-edits.
if review_files:
sys.path.insert(0, str(Path(__file__).parent))
from _claude_md import ensure_bcos_core_block
for rel, upstream_path, local_path, status in review_files:
ref_path = local_root / ".claude" / "bcos-claude-reference.md"
ref_path.parent.mkdir(parents=True, exist_ok=True)
result = ensure_bcos_core_block(
target_claude_md=Path(local_path),
source_claude_md=Path(upstream_path),
recovery_path=ref_path,
)
print()
action = result["action"]
if action == "created":
print(f" CLAUDE.md created from shipped template.")
elif action == "spliced":
print(f" CLAUDE.md: BCOS:CORE block appended at end of file.")
print(f" Your existing content was preserved.")
elif action == "replaced":
print(f" CLAUDE.md: BCOS:CORE block refreshed.")
print(f" Previous CORE saved to .claude/bcos-claude-reference.md")
print(f" (recover any intentional edits from there).")
elif action == "unchanged":
print(f" CLAUDE.md: BCOS:CORE already current.")
# -------------------------------------------------------------- done
print()
print(" Update complete.")
print()
print(" Next: run the document index to refresh metadata:")
print(" python .claude/scripts/build_document_index.py")
print()
# ------------------------------------------------- dispatch: local vs remote
if args.local:
upstream_path = os.path.abspath(args.local)
if not os.path.isdir(upstream_path):
print(f" ERROR: --local path does not exist: {upstream_path}")
sys.exit(1)
run_scan(upstream_path)
else:
upstream_repo = args.upstream or UPSTREAM_REPO
with tempfile.TemporaryDirectory() as tmp:
upstream_root = download_upstream(upstream_repo, args.branch, tmp)
run_scan(upstream_root)
if __name__ == "__main__":
main()
278 files · 9 not served here
- .claude/ECOSYSTEM-MAP.md
- .claude/agents/agent-discovery/find_agents.sh
- .claude/agents/explore/AGENT.md
- .claude/agents/wiki-fetch/AGENT.md
- .claude/bcos-profile
- .claude/bin/python3
- .claude/bin/python3.cmd
- .claude/hook_state/.gitkeep
- .claude/hooks/auto_save_session.sh
- .claude/hooks/post_commit_context_check.py
- .claude/hooks/post_edit_frontmatter_check.py (not served here)
- .claude/hooks/precompact_save.sh
- .claude/quality/atlas-ignore.json
- .claude/quality/ecosystem/config.json
- .claude/quality/ecosystem/learned-rules.json
- .claude/quality/ecosystem/learning-blocklist.json
- .claude/quality/ecosystem/lessons-schema.md
- .claude/quality/ecosystem/lessons-starter.json
- .claude/quality/ecosystem/resolutions.jsonl
- .claude/quality/lifecycle-routing.yml
- .claude/quality/schedule-config.template.json
- .claude/registries/entities.json
- .claude/registries/reference-index.json
- .claude/scripts/_claude_md.py
- .claude/scripts/_jsonl_safe.py
- .claude/scripts/_scheduled_task_cwd.py
- .claude/scripts/_schema_versions.py
- .claude/scripts/_settings_merge.py
- .claude/scripts/_settings_reconciler.py (not served here)
- .claude/scripts/_wiki_budget.py
- .claude/scripts/_wiki_fetch_contract.py
- .claude/scripts/_wiki_http.py
- .claude/scripts/_wiki_job_runner.py
- .claude/scripts/_wiki_lint.py (not served here)
- .claude/scripts/_wiki_schema_merge.py (not served here)
- .claude/scripts/_wiki_triage.py (not served here)
- .claude/scripts/_wiki_yaml.py
- .claude/scripts/analyze_crossrefs.py
- .claude/scripts/analyze_integration.py
- .claude/scripts/append_diary.py
- .claude/scripts/audit_node_configs.py
- .claude/scripts/auto_fix_audit.py
- .claude/scripts/bcos-dashboard/README.md
- .claude/scripts/bcos-dashboard/actions_resolved.py
- .claude/scripts/bcos-dashboard/atlas_collectors.py
- .claude/scripts/bcos-dashboard/atlas_ingest.py
- .claude/scripts/bcos-dashboard/atlas_layout.py
- .claude/scripts/bcos-dashboard/bcos_profile.py
- .claude/scripts/bcos-dashboard/bcos_sync.py
- .claude/scripts/bcos-dashboard/cockpit.py
- .claude/scripts/bcos-dashboard/dashboard.css
- .claude/scripts/bcos-dashboard/dashboard.html
- .claude/scripts/bcos-dashboard/dashboard.js
- .claude/scripts/bcos-dashboard/diary_grouper.py
- .claude/scripts/bcos-dashboard/digest_parser.py
- .claude/scripts/bcos-dashboard/favicon.svg
- .claude/scripts/bcos-dashboard/file_health.py
- .claude/scripts/bcos-dashboard/freshness.py
- .claude/scripts/bcos-dashboard/headless_actions.py
- .claude/scripts/bcos-dashboard/labels.py
- .claude/scripts/bcos-dashboard/learning_panel.py
- .claude/scripts/bcos-dashboard/port_assign.py
- .claude/scripts/bcos-dashboard/run.py
- .claude/scripts/bcos-dashboard/schedule_editor.py
- .claude/scripts/bcos-dashboard/server.py
- .claude/scripts/bcos-dashboard/single_repo.py
- .claude/scripts/bcos_inventory.py
- .claude/scripts/build_document_index.py
- .claude/scripts/check_python_shim_usage.py
- .claude/scripts/cmd_wiki_archive.py
- .claude/scripts/cmd_wiki_init.py
- .claude/scripts/cmd_wiki_lint.py
- .claude/scripts/cmd_wiki_queue_add.py
- .claude/scripts/cmd_wiki_remove.py
- .claude/scripts/cmd_wiki_review.py
- .claude/scripts/cmd_wiki_search.py
- .claude/scripts/consolidate_lessons.py
- .claude/scripts/context_bundle.py
- .claude/scripts/context_index.py
- .claude/scripts/context_search.py
- .claude/scripts/context_search_service.py
- .claude/scripts/cross_repo_fetch.py
- .claude/scripts/digest_sidecar.py
- .claude/scripts/ensure_wiki_zone.py
- .claude/scripts/find_lessons.py
- .claude/scripts/generate_wakeup_context.py
- .claude/scripts/install_global_permissions.py
- .claude/scripts/lifecycle_sweep.py
- .claude/scripts/load_task_profiles.py
- .claude/scripts/load_zone_registry.py
- .claude/scripts/promote_outputs.py
- .claude/scripts/promote_resolutions.py
- .claude/scripts/prune_diary.py
- .claude/scripts/prune_sessions.py
- .claude/scripts/record_daydream.py
- .claude/scripts/record_resolution.py
- .claude/scripts/refresh_ecosystem_state.py
- .claude/scripts/refresh_wiki_index.py
- .claude/scripts/reset_permissions_marker.py
- .claude/scripts/run_wiki_canonical_drift.py
- .claude/scripts/run_wiki_coverage_audit.py
- .claude/scripts/run_wiki_graveyard.py (not served here)
- .claude/scripts/run_wiki_source_refresh.py
- .claude/scripts/run_wiki_stale_propagation.py
- .claude/scripts/scan_docs_structure.py
- .claude/scripts/set_profile.sh
- .claude/scripts/update.py
- .claude/scripts/validate_frontmatter.py
- .claude/scripts/validate_permissions_catalog.py (not served here)
- .claude/scripts/validate_references.py
- .claude/scripts/validate_task_profiles.py
- .claude/scripts/wiki_failed_ingest.py
- .claude/scripts/wiki_schema.py
- .claude/settings.json
- .claude/skills/bcos-wiki/SKILL.md
- .claude/skills/bcos-wiki/archive.md
- .claude/skills/bcos-wiki/bundle.md
- .claude/skills/bcos-wiki/create.md
- .claude/skills/bcos-wiki/ingest.md
- .claude/skills/bcos-wiki/init.md
- .claude/skills/bcos-wiki/lint.md
- .claude/skills/bcos-wiki/promote.md
- .claude/skills/bcos-wiki/queue.md
- .claude/skills/bcos-wiki/references/migration-helpers.md
- .claude/skills/bcos-wiki/references/triage-confidence.md
- .claude/skills/bcos-wiki/refresh.md
- .claude/skills/bcos-wiki/remove.md
- .claude/skills/bcos-wiki/review.md
- .claude/skills/bcos-wiki/run.md
- .claude/skills/bcos-wiki/schema.md
- .claude/skills/bcos-wiki/search.md
- .claude/skills/bcos-wiki/templates/README.md.tmpl
- .claude/skills/bcos-wiki/templates/log.md.tmpl
- .claude/skills/bcos-wiki/templates/overview.md.tmpl
- .claude/skills/bcos-wiki/templates/page-types/glossary.md
- .claude/skills/bcos-wiki/templates/page-types/how-to.md
- .claude/skills/bcos-wiki/templates/page-types/source-summary.md
- .claude/skills/bcos-wiki/templates/protocols/common.md
- .claude/skills/bcos-wiki/templates/protocols/github.md
- .claude/skills/bcos-wiki/templates/protocols/local.md
- .claude/skills/bcos-wiki/templates/protocols/web.md
- .claude/skills/bcos-wiki/templates/protocols/youtube.md
- .claude/skills/bcos-wiki/templates/queue.md.tmpl
- .claude/skills/bcos-wiki/templates/raw/github-README.md.tmpl
- .claude/skills/bcos-wiki/templates/raw/local-README.md.tmpl
- .claude/skills/bcos-wiki/templates/raw/web-README.md.tmpl
- .claude/skills/bcos-wiki/templates/raw/youtube-README.md.tmpl
- .claude/skills/clear-planner/SKILL.md
- .claude/skills/clear-planner/references/discovery-protocol.md
- .claude/skills/clear-planner/references/plan-manifest-schema.md
- .claude/skills/clear-planner/references/planning-workflow-schema.md
- .claude/skills/clear-planner/references/scenario-phases.md
- .claude/skills/context-audit/SKILL.md
- .claude/skills/context-audit/references/clear-principles-checks.md
- .claude/skills/context-ingest/SKILL.md
- .claude/skills/context-mine/SKILL.md
- .claude/skills/context-onboarding/SKILL.md
- .claude/skills/context-routing/SKILL.md
- .claude/skills/context-routing/bundle.md
- .claude/skills/context-routing/search.md
- .claude/skills/core-discipline/SKILL.md
- .claude/skills/core-discipline/references/askuserquestion-pattern.md
- .claude/skills/core-discipline/references/context-rules.md
- .claude/skills/daydream/SKILL.md
- .claude/skills/doc-lint/SKILL.md
- .claude/skills/ecosystem-manager/SKILL.md
- .claude/skills/ecosystem-manager/references/architecture.md
- .claude/skills/ecosystem-manager/references/ecosystem-changes-checklist.md
- .claude/skills/ecosystem-manager/references/learnings-capture.md
- .claude/skills/learning/SKILL.md
- .claude/skills/lessons-consolidate/SKILL.md
- .claude/skills/schedule-dispatcher/SKILL.md
- .claude/skills/schedule-dispatcher/references/auto-fix-whitelist.md
- .claude/skills/schedule-dispatcher/references/finding-categories.md
- .claude/skills/schedule-dispatcher/references/headless-actions.md
- .claude/skills/schedule-dispatcher/references/job-architecture-review.md
- .claude/skills/schedule-dispatcher/references/job-audit-inbox.md
- .claude/skills/schedule-dispatcher/references/job-auto-fix-audit.md
- .claude/skills/schedule-dispatcher/references/job-daydream-deep.md
- .claude/skills/schedule-dispatcher/references/job-daydream-lessons.md
- .claude/skills/schedule-dispatcher/references/job-index-health.md
- .claude/skills/schedule-dispatcher/references/job-lifecycle-sweep.md
- .claude/skills/schedule-dispatcher/references/job-wiki-canonical-drift.md
- .claude/skills/schedule-dispatcher/references/job-wiki-coverage-audit.md
- .claude/skills/schedule-dispatcher/references/job-wiki-failed-ingest.md
- .claude/skills/schedule-dispatcher/references/job-wiki-graveyard.md
- .claude/skills/schedule-dispatcher/references/job-wiki-source-refresh.md
- .claude/skills/schedule-dispatcher/references/job-wiki-stale-propagation.md
- .claude/skills/schedule-tune/SKILL.md
- .claude/skills/skill-discovery/find_skills.sh
- .claude/skills/todo-utilities/SKILL.md
- .claude/skills/todo-utilities/references/todo-patterns.md
- .claude/templates/gitignore.template
- .gitattributes
- .github/ISSUE_TEMPLATE/bug_report.md
- .github/ISSUE_TEMPLATE/config.yml
- .github/ISSUE_TEMPLATE/feature_request.md
- .github/ISSUE_TEMPLATE/new_example.md
- .github/PULL_REQUEST_TEMPLATE.md
- .github/workflows/ci.yml
- .gitignore
- ATTRIBUTION.md
- AUTOGINEER-RUNS.md
- CLAUDE.md
- CODE_OF_CONDUCT.md
- CONTRIBUTING.md
- LICENSE
- README.md
- SECURITY.md
- docs/.onboarding-checklist.md
- docs/_archive/.gitkeep
- docs/_bcos-framework/architecture/collections-zone.md
- docs/_bcos-framework/architecture/component-standards.md
- docs/_bcos-framework/architecture/content-routing.md
- docs/_bcos-framework/architecture/context-routing.md
- docs/_bcos-framework/architecture/context-zones.md
- docs/_bcos-framework/architecture/cross-repo-retrieval.md
- docs/_bcos-framework/architecture/lifecycle-routing.md
- docs/_bcos-framework/architecture/maintenance-lifecycle.md
- docs/_bcos-framework/architecture/metadata-system.md
- docs/_bcos-framework/architecture/permissions-catalog.md
- docs/_bcos-framework/architecture/portfolio-framework-issues-feed.md
- docs/_bcos-framework/architecture/system-design.md
- docs/_bcos-framework/architecture/typed-events.md
- docs/_bcos-framework/architecture/wiki-headless-scripts.md
- docs/_bcos-framework/architecture/wiki-zone.md
- docs/_bcos-framework/guides/adoption-tiers.md
- docs/_bcos-framework/guides/defining-your-context.md
- docs/_bcos-framework/guides/folder-conventions.md
- docs/_bcos-framework/guides/for-non-technical-users.md
- docs/_bcos-framework/guides/getting-started.md
- docs/_bcos-framework/guides/gitignore-profiles.md
- docs/_bcos-framework/guides/maintenance-guide.md
- docs/_bcos-framework/guides/migration-guide.md
- docs/_bcos-framework/guides/private-folder-guide.md
- docs/_bcos-framework/guides/scheduling.md
- docs/_bcos-framework/methodology/clear-principles.md
- docs/_bcos-framework/methodology/context-architecture.md
- docs/_bcos-framework/methodology/decision-framework.md
- docs/_bcos-framework/methodology/document-standards.md
- docs/_bcos-framework/methodology/ownership-specification.md
- docs/_bcos-framework/patterns/client-project-pattern.md
- docs/_bcos-framework/patterns/gtm-pattern.md
- docs/_bcos-framework/patterns/internal-tool-app-pattern.md
- docs/_bcos-framework/patterns/internal-tool-automation-pattern.md
- docs/_bcos-framework/patterns/marketing-pattern.md
- docs/_bcos-framework/patterns/operational-pattern.md
- docs/_bcos-framework/patterns/product-development-pattern.md
- docs/_bcos-framework/patterns/product-service-pattern.md
- docs/_bcos-framework/templates/BCOS-Dashboard.png (not served here)
- docs/_bcos-framework/templates/BCOS-Maintenance-Schedule-Dispatcher.png (not served here)
- docs/_bcos-framework/templates/_context-zones.yml.tmpl
- docs/_bcos-framework/templates/_context.task-profiles.yml.tmpl
- docs/_bcos-framework/templates/_wiki.config.yml.tmpl
- docs/_bcos-framework/templates/_wiki.schema.d.example.yml.tmpl
- docs/_bcos-framework/templates/_wiki.schema.yml.tmpl
- docs/_bcos-framework/templates/context-architecture-canvas.md
- docs/_bcos-framework/templates/context-cluster.md
- docs/_bcos-framework/templates/context-data-point.md
- docs/_bcos-framework/templates/current-state.client-project.md
- docs/_bcos-framework/templates/current-state.internal-tool.md
- docs/_bcos-framework/templates/current-state.md
- docs/_bcos-framework/templates/maintenance-checklist.md
- docs/_bcos-framework/templates/private-starter/README.md
- docs/_bcos-framework/templates/private-starter/release-guide.md
- docs/_bcos-framework/templates/session-diary-starter.md
- docs/_bcos-framework/templates/table-of-context.client-project.md
- docs/_bcos-framework/templates/table-of-context.internal-tool.md
- docs/_bcos-framework/templates/table-of-context.md
- docs/_collections/.gitkeep
- docs/_inbox/.gitkeep
- docs/_inbox/sessions/.gitkeep
- docs/_planned/.gitkeep
- docs/_wiki/.config.yml
- docs/_wiki/.schema.yml
- docs/_wiki/index.md
- docs/_wiki/queue.md
- install.sh
Advantages
- Prevents context rot by surfacing stale information on a configurable schedule. evidence: README.md
- Enforces ownership boundaries to ensure one source of truth per topic. evidence: README.md
- Reduces token usage by providing a structured index that avoids redundant scanning. evidence: CLAUDE.md
- Enables task-aware context retrieval through curated bundles. evidence: README.md
Limitations
- Requires adherence to a specific folder structure and frontmatter schema to function correctly. evidence: README.md
- Maintenance jobs and dispatcher functionality rely on Python and bash being available on the host system. evidence: README.md
Security
Risk level: Medium risk
This brain runs
Agent instructions that run or fetch something (170)
.claude/agents/wiki-fetch/AGENT.md:A 100k-token URL fetched into the main thread by `/wiki run` saturates the context window before a single page lands..claude/agents/wiki-fetch/AGENT.md:| Calling skill | Subcommand | Trigger | |---|---|---| | `bcos-wiki` | `run` Pass 1 | Each URL in the queue → one `wiki-fetch` invocation | | `bcos-wiki` | `refresh` full-tier | Source-summary past `stale_threshold_days` and HEAD signals changed | | `bcos-wiki` | `promote` (Path B) | S …[+132 chars]· uses the network.claude/agents/wiki-fetch/AGENT.md:The cumulative budget guard ([`_wiki_budget.decide_dispatch_strategy`](../../scripts/_wiki_budget.py)) decides whether N sub-agents run in parallel or serial — `parallel` when projected cumulative tokens stay ≤ 80% of the main context limit;.claude/agents/wiki-fetch/AGENT.md:queue an explicit retry tag for next run | | `error.kind: fetch-error` | 4xx/5xx from upstream | Surface to user;.claude/agents/wiki-fetch/AGENT.md:`python .claude/scripts/test_wiki_fetch.py` — asserts this AGENT.md declares the documented input kinds and output fields, that the 4000-token cap is stated, that calling-skill docs reference both `wiki-fetch` and the Task tool, and that the result-schema validator + cumulative budget g …[+47 chars].claude/skills/bcos-wiki/SKILL.md:**`/wiki`** with subcommands: `init`, `init --defaults`, `run`, `queue`, `promote`, `create`, `review`, `archive`, `refresh`, `lint`, `remove`, `schema`, `search`.claude/skills/bcos-wiki/SKILL.md:"Run the wiki refresh".claude/skills/bcos-wiki/SKILL.md:| | `run [<url>]` | implemented | P3 | Path A: batch (no arg) processes all `## Pending` queue items;.claude/skills/bcos-wiki/SKILL.md:single (with URL) auto-queues + ingests | | `queue <url> [tags]` | implemented | P3 | Append URL to `## Pending` of `queue.md` without fetching | | `ingest` | shared protocol | P3 | Internal — called by `run`/`promote`/`create`;.claude/skills/bcos-wiki/SKILL.md:optionally re-pull `builds-on` data points to verify | | `archive <slug>` | implemented | P3 | Soft-delete to `_wiki/.archive/` with dangling-reference scan | | `refresh <slug>` | implemented | P3 | Path A: re-fetch a `source-summary` page (refresh-must-rediscover applies, D-05 two-tie …[+470 chars].claude/skills/bcos-wiki/SKILL.md:`run` → `run.md`.claude/skills/bcos-wiki/SKILL.md:Run `/wiki init` first."* and exit..claude/skills/bcos-wiki/SKILL.md:| Choice | Behavior | |---|---| | Init with defaults + proceed | Run `.claude/scripts/cmd_wiki_init.py` (or equivalent `ensure_wiki_zone.py` call)..claude/skills/bcos-wiki/SKILL.md:Then resume the original subcommand (`create from`, `promote`, `run`, etc.) as if the Guard had passed..claude/skills/bcos-wiki/SKILL.md:| | Full interview + proceed | Read `init.md` and run the 6-question interactive scaffold..claude/skills/bcos-wiki/SKILL.md:The dispatched subcommand files (`create.md`, `promote.md`, `run.md`, `refresh.md`, `lint.md`, `archive.md`, `review.md`, `remove.md`, `schema.md`, `search.md`, `bundle.md`, `queue.md`) all reference *"the `.config.yml` Guard defined in `SKILL.md`"* — they inherit this AskUserQuestion p …[+46 chars].claude/skills/bcos-wiki/SKILL.md:The human reviews diffs and runs `git commit` / `git push` when ready.· uses the network.claude/skills/bcos-wiki/SKILL.md:This applies to `run`, `refresh`, and `create` (when source content is large)..claude/skills/bcos-wiki/SKILL.md:Users who want a binary in collections-as-evidence must run `/collections add` explicitly..claude/skills/bcos-wiki/SKILL.md:├── run.md ← /wiki run [<url>].claude/skills/bcos-wiki/SKILL.md:├── ingest.md ← shared ingest pipeline (called by run/promote/create/refresh).claude/skills/clear-planner/SKILL.md:Step 2: Run Discovery.claude/skills/clear-planner/SKILL.md:{ "step": 2, "name": "Run Discovery", "status": "in_progress" }.claude/skills/clear-planner/SKILL.md:**Run all three discovery scripts:**.claude/skills/clear-planner/SKILL.md:bash .claude/agents/agent-discovery/find_agents.sh.claude/skills/clear-planner/SKILL.md:bash .claude/skills/skill-discovery/find_skills.sh.claude/skills/clear-planner/SKILL.md:python .claude/scripts/find_lessons.py --tags "#{scenarioType}".claude/skills/clear-planner/SKILL.md:Run discovery scripts (Step 2 results).claude/skills/clear-planner/SKILL.md:| | ------------------- | ------------------------------------ | --------------------------------------------------------- | ------------------- | | Integration Audit | Detect stale references in ecosystem | `python .claude/scripts/analyze_integration.py --staged` + AI review | **YES …[+455 chars].claude/skills/clear-planner/SKILL.md:| Scenario | Key Requirement | | ----------------- | ------------------------------------------------------------------ | | **AGENTING** | Check for ecosystem overlaps + run integration audit before commit | | **DOCUMENTAT …[+76 chars].claude/skills/context-audit/SKILL.md:Run all five audit categories against the scoped files..claude/skills/context-audit/SKILL.md:python .claude/scripts/build_document_index.py.claude/skills/context-ingest/SKILL.md:| Input shape | Dispatch to | Why | |-------------|-------------|-----| | HTTP/HTTPS URL (article, GitHub, YouTube) | `/wiki run <url>` (the `bcos-wiki` skill, Path A) | Wiki owns external-source ingest, banner citations, schema validation, refresh tier | | Path inside `docs/_inbox/` a …[+508 chars].claude/skills/context-ingest/SKILL.md:If the input is mixed (e.g. Slack export *and* a URL), do mine first, then handle the URL via `/wiki run` separately, then return to ingest for whatever's left..claude/skills/context-ingest/SKILL.md:Run `python .claude/scripts/build_document_index.py` after material changes.claude/skills/context-ingest/SKILL.md:**→ Rebuild Document Index** — Always: `python .claude/scripts/build_document_index.py`.claude/skills/context-ingest/SKILL.md:**→ context-audit** — If a new data point was created: "Want me to run a quick CLEAR audit on the new doc?".claude/skills/context-mine/SKILL.md:Recommend: "Run context-ingest to classify and route these items".claude/skills/context-onboarding/SKILL.md:| What you see | What you do | |---|---| | User shares a URL, pitch deck, or describes their business | Gather from those sources, ask 2-3 follow-ups if needed | | Repo already has docs/, README, markdown files with business content | Scan the repo, map what exists | | User drops files …[+394 chars]· uses the network.claude/skills/context-onboarding/SKILL.md:Before anything else, run **once** per onboarding session to make sure the BCOS-managed instructions are present in `CLAUDE.md`..claude/skills/context-onboarding/SKILL.md:This catches the `git clone`-without-`install.sh` case: if `CLAUDE.md` exists but lacks the `<!-- BCOS:CORE:START -->` / `<!-- BCOS:CORE:END -->` markers, the framework section is missing or unstructured.· uses the network.claude/skills/context-onboarding/SKILL.md:If `.claude/bcos-claude-reference.md` doesn't exist yet (fresh clone), point `--source` at the upstream template available in this repo's tree (the same file install.sh would have copied)..claude/skills/context-onboarding/SKILL.md:**First-run routing principle:** onboarding is allowed to identify all BCOS zones, but it should only create active data points after the user approves the architecture..claude/skills/context-onboarding/SKILL.md:| Material | First-run handling | |---|---| | Canonical facts, current decisions, project/task/business reality | Draft active data points in `docs/*.md` | | Raw notes, unsorted snippets, uncertain material | Keep in `docs/_inbox/` until triaged | | Future ideas, plans, or maybes | Par …[+578 chars].claude/skills/context-onboarding/SKILL.md:Options: **Activate** (set all to active, run index + wake-up) / **Adjust** (tell me what to fix).claude/skills/context-onboarding/SKILL.md:Run `python .claude/scripts/build_document_index.py` to generate the Document Index with DOMAIN one-liners.claude/skills/context-onboarding/SKILL.md:Run `python .claude/scripts/generate_wakeup_context.py` to generate the Wake-Up Context for instant session orientation.claude/skills/context-onboarding/SKILL.md:The checklist ships with install at `docs/.onboarding-checklist.md`..claude/skills/context-onboarding/SKILL.md:Ensure the `.claude/hook_state/` directory exists (it usually does from install.sh — check and create if missing)..claude/skills/context-onboarding/SKILL.md:the dispatcher will create it on first run..claude/skills/context-onboarding/SKILL.md:**Run the catalog drift guard:**.claude/skills/context-onboarding/SKILL.md:python .claude/scripts/validate_permissions_catalog.py.claude/skills/context-onboarding/SKILL.md:python .claude/scripts/update.py.claude/skills/context-onboarding/SKILL.md:Re-run the validator to confirm clean..claude/skills/context-onboarding/SKILL.md:If the answer is "Yes, multi-repo" (or the user confirms after explanation), run:.claude/skills/context-onboarding/SKILL.md:python .claude/scripts/install_global_permissions.py.claude/skills/context-onboarding/SKILL.md:Question: "When should the morning dispatcher run?".claude/skills/context-onboarding/SKILL.md:Run the schedule-dispatcher skill to execute today's scheduled CLEAR maintenance. It will:.claude/skills/context-onboarding/SKILL.md:3. Execute each job in sequence, appending one diary entry per job.claude/skills/context-onboarding/SKILL.md:The portfolio aggregator picks it up on the next dispatcher run..claude/skills/context-onboarding/SKILL.md:The dispatcher will run in the wrong directory and writes meant for this repo's `docs/_inbox/` will be blocked..claude/skills/context-onboarding/SKILL.md:If "Recreate", call `mcp__scheduled-tasks__delete_event` (or the equivalent delete tool) on the bad task, then re-run Step 6d..claude/skills/context-onboarding/SKILL.md:That's intentional — fresh setups should over-monitor for the first 1-2 weeks until the auto-tuner suggests reductions after green-run streaks..claude/skills/context-onboarding/SKILL.md:Let the user invoke the first run on their terms..claude/skills/context-onboarding/SKILL.md:A fresh install has nothing to migrate and should never see the word..claude/skills/core-discipline/SKILL.md:**Significant change** (restructure a cluster, create new skills) → use clear-planner, run the full workflow.claude/skills/core-discipline/SKILL.md:| Task Type | Action | | ------------------------- | ---------------------- | | Questions, commands | Respond directly | | Single-file fixes | Just do it | | Small changes (1-3 files) | Think briefly, execute |.claude/skills/core-discipline/SKILL.md:A scheduled dispatcher run finishes clean green with zero findings (one-line summary keeps the dashboard "Ready" status meaningful).claude/skills/core-discipline/SKILL.md:**Special case — wrapping scripts with built-in prompts** (like `update.py`'s `[y/N]` prompt): invoke the script with `--dry-run` first, parse the output, surface the summary via `AskUserQuestion`, then re-invoke with `--yes` based on the user's choice..claude/skills/daydream/SKILL.md:If the file doesn't exist, this is the first run — use 2 weeks ago as the baseline..claude/skills/daydream/SKILL.md:# Read last run timestamp (or default to 2 weeks ago).claude/skills/daydream/SKILL.md:cat .claude/quality/last-daydream.txt 2>/dev/null || echo "no previous run".claude/skills/daydream/SKILL.md:git log --since="{last_daydream_date}" --name-only --pretty=format:"%h %s (%ar)" -- docs/ ':!docs/_bcos-framework/methodology/' ':!docs/_bcos-framework/guides/' ':!docs/_bcos-framework/templates/'.claude/skills/daydream/SKILL.md:Report "No document changes since last run" and skip to Phase 3 (Imagine) for forward-looking reflection only..claude/skills/daydream/SKILL.md:git diff {last_daydream_commit}..HEAD -- docs/path/to/changed-file.md.claude/skills/daydream/SKILL.md:python .claude/scripts/build_document_index.py --dry-run.claude/skills/daydream/SKILL.md:python .claude/scripts/generate_wakeup_context.py.claude/skills/daydream/SKILL.md:**Step 5b: Run maintenance scripts**.claude/skills/daydream/SKILL.md:Daydream is the natural time to run periodic maintenance:.claude/skills/daydream/SKILL.md:python .claude/scripts/prune_sessions.py.claude/skills/daydream/SKILL.md:python .claude/scripts/prune_diary.py.claude/skills/daydream/SKILL.md:python .claude/scripts/generate_wakeup_context.py.claude/skills/daydream/SKILL.md:python .claude/scripts/analyze_crossrefs.py.claude/skills/daydream/SKILL.md:**Step 6: Record this run**.claude/skills/daydream/SKILL.md:python .claude/scripts/record_daydream.py.claude/skills/daydream/SKILL.md:**Document Index** — Run `python .claude/scripts/build_document_index.py` if files changed.claude/skills/doc-lint/SKILL.md:If `.md`: Run markdown quality checks and cross-reference validation.claude/skills/doc-lint/SKILL.md:If `.json`: Run JSON structure validation.claude/skills/doc-lint/SKILL.md:Px_001: Run markdown quality check -> doc-lint (markdown category).claude/skills/doc-lint/SKILL.md:Px_002: Run example code validation -> doc-lint (cross_reference category).claude/skills/doc-lint/SKILL.md:Px_001: Run JSON structure validation -> doc-lint (json_structure category).claude/skills/doc-lint/SKILL.md:Px_002: Run markdown quality check -> doc-lint (markdown category).claude/skills/ecosystem-manager/SKILL.md:Run discovery to see what exists:.claude/skills/ecosystem-manager/SKILL.md:bash .claude/agents/agent-discovery/find_agents.sh.claude/skills/ecosystem-manager/SKILL.md:bash .claude/skills/skill-discovery/find_skills.sh.claude/skills/ecosystem-manager/SKILL.md:Run it before committing..claude/skills/ecosystem-manager/SKILL.md:python .claude/scripts/analyze_integration.py --uncommitted.claude/skills/ecosystem-manager/SKILL.md:Coverage gaps in install.sh, settings.json, state.json, .gitignore.claude/skills/ecosystem-manager/SKILL.md:Add fix tasks to the plan and execute them before committing..claude/skills/ecosystem-manager/SKILL.md:[ ] **install.sh installs new files**.claude/skills/ecosystem-manager/SKILL.md:Run after major development sessions or as part of monthly architecture review..claude/skills/ecosystem-manager/SKILL.md:Run `python .claude/scripts/wiki_schema.py list` to inspect page-types, lint-checks, and auto-fixes from `_wiki/.schema.yml` or the framework fallback..claude/skills/ecosystem-manager/SKILL.md:Run all 4 CI checks locally:.claude/skills/ecosystem-manager/SKILL.md:python .github/scripts/validate_frontmatter.py # YAML metadata on all managed markdown.claude/skills/ecosystem-manager/SKILL.md:python .github/scripts/validate_references.py # All registry paths resolve + state.json accuracy.claude/skills/ecosystem-manager/SKILL.md:python .claude/scripts/analyze_integration.py --ci # Ecosystem wiring (install.sh, settings.json coverage).claude/skills/learning/SKILL.md:**Mechanism:** `python .claude/scripts/promote_resolutions.py` (the module's `__main__` calls `regenerate()`)..claude/skills/learning/SKILL.md:Run the matching subcommand directly..claude/skills/lessons-consolidate/SKILL.md:python .claude/scripts/consolidate_lessons.py.claude/skills/schedule-dispatcher/SKILL.md:Run `python .claude/scripts/update.py` first.".claude/skills/schedule-dispatcher/SKILL.md:Report to the user: "schedule-config.json is malformed — fix before the dispatcher can run..claude/skills/schedule-dispatcher/SKILL.md:For each entry in `jobs`, decide if it should run today..claude/skills/schedule-dispatcher/SKILL.md:| `schedule` value | Runs when | |--------------------|----------------------------------------------------| | `"daily"` | Every day | | `"mon"`..`"sun"` | Only on that weekday …[+549 chars].claude/skills/schedule-dispatcher/SKILL.md:**For on-demand dispatch** (user said "run the audit-inbox job"): skip this step, run only the named job..claude/skills/schedule-dispatcher/SKILL.md:Build an ordered list of jobs to run..claude/skills/schedule-dispatcher/SKILL.md:python .claude/scripts/context_index.py --write.claude/skills/schedule-dispatcher/SKILL.md:The cache TTL is 10 min (longer than a full dispatcher cycle), so all jobs in this run hit the same in-memory snapshot..claude/skills/schedule-dispatcher/SKILL.md:Last run timestamp per job?.claude/skills/schedule-dispatcher/SKILL.md:Use the helper script — it creates `.claude/hook_state/` on first run and matches the allowlisted command prefix so it never prompts:.claude/skills/schedule-dispatcher/SKILL.md:python .claude/scripts/append_diary.py '{"ts":"2026-04-15T09:04:12","job":"index-health","verdict":"green","findings_count":0,"auto_fixed":[],"actions_needed":[],"duration_s":4}'.claude/skills/schedule-dispatcher/SKILL.md:**Fallback:** when `.bcos-umbrella.json` is absent (standalone BCOS install with no umbrella), preflight reduces to the `../` + absolute-path scans — no sibling-name list to check against..claude/skills/schedule-dispatcher/SKILL.md:After Step 4 completes (last job returned), verify that **every job listed in Step 2's run-list produced exactly one diary entry in this dispatcher tick**..claude/skills/schedule-dispatcher/SKILL.md:Read back the diary entries appended during this tick (use the dispatcher's in-memory record, or the tail of `.claude/hook_state/schedule-diary.jsonl` filtered to the current run's `ts` prefix if you're running on-demand)..claude/skills/schedule-dispatcher/SKILL.md:**Added in schema 1.1.0.** Before applying auto-fixes (Step 5) or rendering the digest (Step 7), enrich each finding emitted in Step 4 with three computed fields and produce the run's headline string..claude/skills/schedule-dispatcher/SKILL.md:**Match against prior tick.** Scan diary entries from the **immediately-prior dispatcher tick** (the most-recent run before today, identified by the latest `ts` < today's run window)..claude/skills/schedule-dispatcher/SKILL.md:| Run shape | Headline template | |---|---| | Green clean (0 findings, 0 framework) | "{Nth consecutive green run.}{recovery callout if any job verdict flipped error→green this tick.}" | | Green with frequency suggestions only | "All {N} jobs green..claude/skills/schedule-dispatcher/SKILL.md:And the run has a `headline` string ready for Step 7..claude/skills/schedule-dispatcher/SKILL.md:For each job run today, check recent diary:.claude/skills/schedule-dispatcher/SKILL.md:**Last run was `error`** → suggest investigating, not frequency change.claude/skills/schedule-dispatcher/SKILL.md:Both are overwritten each run..claude/skills/schedule-dispatcher/SKILL.md:Conditional sections render ONLY when their counts are non-zero — a green clean run is ~5 lines, an amber run with 5 findings is ~40 lines..claude/skills/schedule-dispatcher/SKILL.md:| 1 | `{emitted_by}` | `{primary_attr}` | {one-line meaning} | {`🔁 Nth run` if consecutive_runs ≥ 3, else blank} |.claude/skills/schedule-dispatcher/SKILL.md:Run at {ISO timestamp} · `.claude/hook_state/schedule-diary.jsonl`.claude/skills/schedule-dispatcher/SKILL.md:verdict emoji + finding count + inline status markers in Note column | | `💡 Suggestions` | `≥1` `frequency-suggestion` finding | Bullet list | | Footer | Always | Run timestamp, diary path, auto-commit status |.claude/skills/schedule-dispatcher/SKILL.md:| Scenario | Verdict bar example | Top line | Action hint | |---|---|---|---| | Green clean | `**🟢 BCOS green** · 1 ran · 0 findings · 0 fixed · 4s` | `Headline string from Step 4c, e.g. "10th consecutive green run."` | `→ Nothing to act on..claude/skills/schedule-dispatcher/SKILL.md:Run `git rev-parse --abbrev-ref HEAD` to get the current branch..claude/skills/schedule-dispatcher/SKILL.md:This is the per-tick safety property: a stray hand-edit to a "generated" file on a day its owning job did not run still blocks auto-commit..claude/skills/schedule-dispatcher/SKILL.md:Globs are resolved against `git status --porcelain` paths (same surface the clean-tree rule already inspects)..claude/skills/schedule-dispatcher/SKILL.md:**Emit the `job-missing-outputs-declaration` framework-finding only when** the job's run would have changed at least one path *outside* `GLOBAL_ALLOWED` (i.e. a path that *could* have been auto-committable had it been declared)..claude/skills/schedule-dispatcher/SKILL.md:Run `git status --porcelain`..claude/skills/schedule-dispatcher/SKILL.md:`git commit -m "bcos: daily maintenance {YYYY-MM-DD}"` — no push, ever..claude/skills/schedule-dispatcher/SKILL.md:A BCOS install with no umbrella still writes the log — it just sits locally until somebody (or the dashboard) reads it..claude/skills/schedule-dispatcher/SKILL.md:The last thing the dispatcher does depends on whether the run produced anything that needs user judgement..claude/skills/schedule-dispatcher/SKILL.md:Otherwise — clean green run, zero findings, zero suggestions — output a short summary and stop..claude/skills/schedule-dispatcher/SKILL.md:**Why this rule:** if every run always asked a question, every scheduled run would show as "Awaiting input" in the dashboard even on clean days..claude/skills/schedule-dispatcher/SKILL.md:Or even shorter when the user is watching an on-demand run:.claude/skills/schedule-dispatcher/SKILL.md:("Do you want architecture review to run weekly?" is too abstract — `schedule-tune` handles that).claude/skills/schedule-dispatcher/SKILL.md:**Retry the failed job(s)** → re-run only the errored jobs (on-demand mode), then ask again with the new result.claude/skills/schedule-dispatcher/SKILL.md:If the user says "run the {job-name} job now" or "run today's maintenance now":.claude/skills/schedule-dispatcher/SKILL.md:Skip the schedule predicate — run only the named job(s).claude/skills/schedule-dispatcher/SKILL.md:## On-demand run — {HH:MM} ({job-name}).claude/skills/schedule-dispatcher/SKILL.md:If `daily-digest.md` does not yet exist (no scheduled run happened today), create it with a minimal header before appending the on-demand section..claude/skills/schedule-dispatcher/SKILL.md:DO append a diary entry per job with `"trigger":"on-demand"` so the run is tracked in history.claude/skills/schedule-dispatcher/SKILL.md:Run another job.claude/skills/schedule-dispatcher/SKILL.md:The morning scheduled run always OVERWRITES `daily-digest.md` fresh — so yesterday's on-demand sections are not preserved in the digest (diary retains them)..claude/skills/schedule-dispatcher/SKILL.md:Every dispatcher run produces either a digest OR a user-facing error message..claude/skills/schedule-dispatcher/SKILL.md:`schedule-tune` — user-facing skill for changing config ("run audit twice a week").claude/skills/schedule-dispatcher/SKILL.md:If a run was wrong, add a corrective entry, don't mutate history..claude/skills/schedule-tune/SKILL.md:If you haven't set up BCOS scheduling yet, run `context-onboarding` Step 6..claude/skills/schedule-tune/SKILL.md:**Utterances:** *"run audit twice a week"*, *"change daydream to every 3 days"*, *"switch architecture review to quarterly"*, *"run index-health on weekdays only"*, *"audit on Tuesdays and Fridays"*.claude/skills/schedule-tune/SKILL.md:**Utterances:** *"run the dispatcher at 08:30"*, *"move morning maintenance to 07:00"*.claude/skills/schedule-tune/SKILL.md:Update the actual scheduled task's cron via `mcp__scheduled-tasks__update_scheduled_task` — that's what actually moves the run.claude/skills/schedule-tune/SKILL.md:**Utterances:** *"what's my maintenance schedule?"*, *"when does audit run?"*, *"is architecture-review enabled?"*.claude/skills/schedule-tune/SKILL.md:If the user proposes a cron that would run more than once per day, refuse: *"Dispatcher is designed to run once daily..claude/skills/schedule-tune/SKILL.md:| User says | Config edit | |----------------------------------------|----------------------------------------------------------------| | "run audit on Tuesday instead of Friday" | `jobs.audit-inbox.schedu …[+1012 chars].claude/skills/todo-utilities/SKILL.md:**Sequential Agent Invocation** — Tasks run one after anotherCLAUDE.md:**Small changes (1-3 files)** — think briefly, execute.CLAUDE.md:Auto-generated by `python .claude/scripts/generate_wakeup_context.py`.CLAUDE.md:When unsure, run `context-ingest` and let it propose the route.CLAUDE.md:**Post-work handoffs:** After integrating new content, offer to (a) rebuild the document index, (b) update related data points, (c) run an audit if architecture shifted.
Hooks (5)
.claude/settings.json(Stop):bash "$CLAUDE_PROJECT_DIR/.claude/hooks/auto_save_session.sh".claude/settings.json(PreCompact):bash "$CLAUDE_PROJECT_DIR/.claude/hooks/precompact_save.sh".claude/settings.json(PostToolUse):"$CLAUDE_PROJECT_DIR/.claude/bin/python3" "$CLAUDE_PROJECT_DIR/.claude/hooks/post_edit_frontmatter_check.py".claude/settings.json(PostToolUse):"$CLAUDE_PROJECT_DIR/.claude/bin/python3" "$CLAUDE_PROJECT_DIR/.claude/hooks/post_edit_frontmatter_check.py".claude/settings.json(PostToolUse):"$CLAUDE_PROJECT_DIR/.claude/bin/python3" "$CLAUDE_PROJECT_DIR/.claude/hooks/post_commit_context_check.py"
Install scripts (1)
install.sh:sh install.sh
- Medium risk: runs-instruction-instruction-network (.claude/agents/wiki-fetch/AGENT.md:93)
- Medium risk: runs-instruction-instruction-network (.claude/skills/bcos-wiki/SKILL.md:150)
- Medium risk: runs-instruction-instruction-network (.claude/skills/context-onboarding/SKILL.md:33)
- Medium risk: runs-instruction-instruction-network (.claude/skills/context-onboarding/SKILL.md:50)
- Low risk: scripts-present (.claude/agents/agent-discovery/find_agents.sh)
- Low risk: scripts-present (.claude/bin/python3)
- Low risk: scripts-present (.claude/hooks/auto_save_session.sh)
- Low risk: scripts-present (.claude/hooks/post_commit_context_check.py)
- Low risk: scripts-present (.claude/hooks/post_edit_frontmatter_check.py)
- Low risk: scripts-present (.claude/hooks/precompact_save.sh)
- Low risk: scripts-present (.claude/scripts/analyze_crossrefs.py)
- Low risk: scripts-present (.claude/scripts/analyze_integration.py)
- Low risk: scripts-present (.claude/scripts/append_diary.py)
- Low risk: scripts-present (.claude/scripts/audit_node_configs.py)
- Low risk: scripts-present (.claude/scripts/auto_fix_audit.py)
- Low risk: scripts-present (.claude/scripts/bcos_inventory.py)
- Low risk: scripts-present (.claude/scripts/build_document_index.py)
- Low risk: scripts-present (.claude/scripts/cmd_wiki_archive.py)
- Low risk: scripts-present (.claude/scripts/cmd_wiki_init.py)
- Low risk: scripts-present (.claude/scripts/cmd_wiki_lint.py)
- Low risk: scripts-present (.claude/scripts/cmd_wiki_queue_add.py)
- Low risk: scripts-present (.claude/scripts/cmd_wiki_remove.py)
- Low risk: scripts-present (.claude/scripts/cmd_wiki_review.py)
- Low risk: scripts-present (.claude/scripts/cmd_wiki_search.py)
- Low risk: scripts-present (.claude/scripts/consolidate_lessons.py)
- Low risk: scripts-present (.claude/scripts/context_bundle.py)
- Low risk: scripts-present (.claude/scripts/context_index.py)
- Low risk: scripts-present (.claude/scripts/context_search.py)
- Low risk: scripts-present (.claude/scripts/digest_sidecar.py)
- Low risk: scripts-present (.claude/scripts/find_lessons.py)
- Low risk: scripts-present (.claude/scripts/generate_wakeup_context.py)
- Low risk: scripts-present (.claude/scripts/install_global_permissions.py)
- Low risk: scripts-present (.claude/scripts/lifecycle_sweep.py)
- Low risk: scripts-present (.claude/scripts/load_task_profiles.py)
- Low risk: scripts-present (.claude/scripts/load_zone_registry.py)
- Low risk: scripts-present (.claude/scripts/promote_resolutions.py)
- Low risk: scripts-present (.claude/scripts/prune_diary.py)
- Low risk: scripts-present (.claude/scripts/prune_sessions.py)
- Low risk: scripts-present (.claude/scripts/record_daydream.py)
- Low risk: scripts-present (.claude/scripts/record_resolution.py)
- Low risk: scripts-present (.claude/scripts/refresh_ecosystem_state.py)
- Low risk: scripts-present (.claude/scripts/refresh_wiki_index.py)
- Low risk: scripts-present (.claude/scripts/run_wiki_canonical_drift.py)
- Low risk: scripts-present (.claude/scripts/run_wiki_coverage_audit.py)
- Low risk: scripts-present (.claude/scripts/run_wiki_graveyard.py)
- Low risk: scripts-present (.claude/scripts/run_wiki_source_refresh.py)
- Low risk: scripts-present (.claude/scripts/run_wiki_stale_propagation.py)
- Low risk: scripts-present (.claude/scripts/scan_docs_structure.py)
- Low risk: scripts-present (.claude/scripts/set_profile.sh)
- Low risk: scripts-present (.claude/scripts/update.py)
Attribution and licence
- First committed by
walm00
- Publisher
- Guntis Coders (Community)
- Source
- walm00/business-context-os · commit 4635683
- Licence
- MIT License (files served here)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Contributors
- walm00
AutoGineer is not affiliated with or endorsed by walm00.
Install from source
9 of its files are not served here, so there is no ZIP. walm00/business-context-os at 4635683