KF CPTO — Open Knowledge Bundle
Bundle OKF 0.1 · 5 conceitos · Katty-Fashion/kf-cpto
Open source Repository Open in the app JSON README (API)
About
# KF CPTO — Open Knowledge Bundle
This directory is a conformant OKF v0.1 bundle: a directed graph of markdown
concepts cross-linked by absolute bundle-relative paths. It is generated by
`scripts/okf_export.py` from already-parsed kanban and calendar data — never
re-parse individual repo files; consume this bundle instead.
## Sections
- [Projects](/projects/index.md) — 6 tracked repos
- [Tasks](/tasks/index.md) — 69 task concepts
- [Metrics](/metrics/index.md) — LOE and RAG status definitions
- [Milestones](/milestones/index.md) — Migration calendar milestones
- [log.md](/log.md) — Change history
## Effort Summary
| Metric | Value |
| :--- | :--- |
| Total declared effort | 358d |
| Done | 236d |
| Remaining | 123d |
> **Effort semantics:** `Nd` = person-days as declared in each `kanban.md`.
> See [/metrics/loe.md](/metrics/loe.md) for the full definition and the
> distinction from `gantt.yml` working-day spans.
Details
- Kind
- OKF bundles
- Topic
- Files & documents
- Publisher
- katty-fashion
- Origin
- okf_github
- Category
- dados
- Version
- 0.1
- Last push
- 2026-09-07T04:19:41Z
- Repository state
- ativo
- Language
- Python
- Added
- 2026-09-08 16:04:09
- Updated
- 2026-09-12 17:10:26
- Origin id
Katty-Fashion/kf-cpto:docs/okf/index.md
README
# KF-CPTO — Git-Native Project Management Dashboard
> **Single Pane of Glass** for KF Team projects — zero-config aggregation of Kanban boards, calendars, LOE tracking, and dependency graphs across all repositories.
## Overview
KF-CPTO is a centralized dashboard that **automatically discovers** and aggregates project management data from KF Team repositories. Any repo in the `katty-fashion` org with a `kanban.md` file is automatically included — no manual configuration required.
- **Unified Kanban Board** — All project tasks in one view
- **Sprint Calendar & Migration Gantt** — Visual timelines with Mermaid Gantt charts
- **LOE (Level of Effort) Reports** — Effort tracking by project and assignee
- **Dependency Graph** — Obsidian-style directed graph showing inter-project dependencies
- **Google Sheets Integration** — Automatic LOE sync for reporting
- **GitHub Pages Deployment** — Live at `https://katty-fashion.github.io/kf-cpto/`
- **Kanban Generator** — A local script that splits the migration plan-of-record into distinct per-repo `kanban.md` files by discipline (see [Generate Per-Repo Kanbans](#generate-per-repo-kanbans-from-the-migration-plan))
- **Activity Sync Skill** — A local Claude skill that reconciles each repo's `kanban.md` against *real* git activity (merged PRs, active branches) and writes the corrections back (see below)
- **Knowledge Bundle (OKF)** — An agent-consumable [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/tree/main/okf) bundle at `docs/okf/`, generated alongside the dashboard so our own tooling and agents can read the whole picture without bespoke parsing (see [Knowledge Bundle (OKF)](#knowledge-bundle-okf--agent-consumable-project-memory))
## Activity Sync — Keep the Board Honest
`activity-sync` is a **local Claude Code skill** (in `.claude/skills/activity-sync/`) that turns the dashboard from hand-maintained into **activity-driven**: it reads what actually happened in each tracked repo, proposes status corrections, and writes them back so the dashboard reflects reality. It runs **on your machine**, never in CI — the CI pipeline stays self-contained and just renders whatever `kanban.md` files say.
### Setup (once)
```bash
export KF_PAT=your-token # needs Contents: Read AND Write (write-back pushes)
pip install -r requirements.txt # installs pyyaml, ruamel.yaml, requests
```
Tracked repos live under a gitignored `repos-local/` directory beside the scripts.
### The 3 steps
```bash
# 1. ENUMERATE — clone/refresh tracked repos and read their kanban.md
python .claude/skills/activity-sync/bootstrap.py # first run only: clone + seed markers
python .claude/skills/activity-sync/repo_enum.py # fetch + parse every tracked repo
# 2. PREVIEW — dry-run reconciliation: show what WOULD change, write nothing
python .claude/skills/activity-sync/reconcile.py --dry-run
# 3. WRITE BACK — apply the changes, one batch confirm, then push (triggers the dashboard)
python .claude/skills/activity-sync/writeback.py # add --dry-run to preview the write plan
```
**What each step does:**
| Step | Script | What happens |
| :--- | :--- | :--- |
| 1. Enumerate | `repo_enum.py` | `git fetch` each tracked repo, parse `kanban.md` (read-only) |
| 2. Reconcile | `reconcile.py` | Match git signals to tasks — merged PR/closed issue → `Done`, active branch → `In Progress`; reverted merges and commit-message keywords are ignored. Prints a change list; writes nothing |
| 3. Write back | `writeback.py` | Sanitizes Mermaid-breaking characters, applies the status changes, asks for **one** confirmation, then commits & pushes to each repo's default branch — which fires the dashboard rebuild |
**Good to know:**
- **Dry-run first.** Always safe — `reconcile.py --dry-run` and `writeback.py --dry-run` change nothing.
- **One confirmation.** Write-back shows a single summary for all repos and asks once — no per-repo prompts.
- **Conflicts are skipped, not forced.** If a repo's local copy is behind its remote, that repo is logged `[CONFLICT]` and skipped; the others still go through.
- **Idempotent.** Re-running on an already-correct repo produces zero changes.
- **Recovery manifest.** Every run writes a JSON record of what succeeded/failed to `.claude/skills/activity-sync/manifests/` (gitignored).
> Full reference (output formats, conflict recovery, env vars): [`.claude/skills/activity-sync/SKILL.md`](.claude/skills/activity-sync/SKILL.md)
## Generate Per-Repo Kanbans from the Migration Plan
The three platform repos — `kf-platform`, `kf-be-platform`, `kf-fe-platform` — share **one** migration plan. Rather than hand-maintaining three boards, `scripts/generate_kanban.py` keeps a single **plan-of-record** and splits it into distinct per-repo `kanban.md` files by discipline:
| Discipline (Assignee) | Owning repo |
| :--- | :--- |
| FE-only (`@<frontend>`) | `kf-fe-platform` |
| BE-only (`@<backend>`) | `kf-be-platform` |
| FE + BE (`@<frontend> + @<backend>`) | `kf-platform` (cross-stack umbrella) |
Every task lands in **exactly one** repo, so the LOE export sums cleanly with **no double-counting**.
### The plan-of-record
`docs/_data/migration_plan.yml` is the editable source of truth (seeded once from `kf-platform`'s curated board). **Edit this file** to change tasks, effort, dates, or assignees — then regenerate. Effort is true **person-days** (`Nd`), not calendar span.
### Workflow
```bash
# 1. Edit the plan
$EDITOR docs/_data/migration_plan.yml
# 2. Preview the split — writes nothing
python scripts/generate_kanban.py
# 3. Apply — sync each clone to origin, regenerate, one batch confirm, commit + push
python scripts/generate_kanban.py --apply --no-push # commit locally, push via your SSH
python scripts/generate_kanban.py --apply # commit + push (needs KF_PAT)
```
The push fires each repo's `notify-kf-cpto.yml` dispatch → the dashboard + Sheet rebuild automatically.
**Guarantees:**
- **Only `kanban.md` is committed** — never unrelated files.
- **Mindful of others.** Before regenerating, each clone is fast-forwarded to origin so our commit lands *on top* of everyone's work — never a force-push, never discarding others' commits. A repo whose `kanban.md` diverged on origin is logged `[CONFLICT]` and skipped.
- **Status merge.** A repo's own valid status wins over the plan's, so regenerating never reverts statuses set by Activity Sync.
- **Idempotent.** Re-running with no plan change writes nothing.
- **First run only:** if `migration_plan.yml` is missing it is seeded from `kf-platform`; use `--reseed` to rebuild it from a full-plan `kf-platform` board.
> Full reference: the `[GENERATE]` section of [`.claude/skills/activity-sync/SKILL.md`](.claude/skills/activity-sync/SKILL.md)
## Weekly Update Runbook — Refresh Statuses & Prep Reporting
**How to launch:** in Claude Code (this repo), trigger the **`activity-sync`** skill — say
`activity sync`, `reconcile task statuses`, or `write back kanban`. It runs the flow below
end-to-end with one batch confirmation. For interactive board cleanup (rename / re-own /
delete / add tasks by number), trigger **`kanban-groom`** — say `groom the kanban` or
`list <repo> tasks`.
**No-resurfacing guarantee:** every automated path is **forward-only** (`Todo → In Progress
→ Review → Done`). A solved task can never reopen via a weekly run:
- `reconcile.py` filters non-advancing proposals (RECON-07) and caps branch signals at
In Progress; `writeback.py` re-checks and drops any non-forward proposal (`[GUARD]`).
- `generate_kanban.py` merges plan-vs-board by **max rank** — a plan edit can advance a
board but never downgrade it (`[GUARD]` logged) — and `--apply` syncs the merged truth
back into `migration_plan.yml` so the plan never drifts behind the boards.
- Downgrades (deliberately reopening a task) are only possible interactively via
`kanban-groom` or a manual PR — never by automation.
Run weekly (or before any reporting review):
```bash
export KF_PAT=your-token # or: export KF_PAT="$(gh auth token)"
# 1. REFRESH — fetch every tracked repo and read its declared state
python .claude/skills/activity-sync/repo_enum.py
# 2. MINE — preview activity-driven corrections (writes nothing)
# [TIER-1] merged PRs / closed issues → Done [TIER-2] active branches → In Progress
# [TIER-3] any repo carrying a GSD .planning/ folder gets an [INFO] progress line
# (milestone · phases · plans · %) — use it to judge status upgrades
python .claude/skills/activity-sync/reconcile.py --dry-run
# 3. ALIGN — apply judgment to the plan-of-record
# Statuses live on the prefixed [F{faza}.S{sprint}.Name] tasks
$EDITOR docs/_data/migration_plan.yml
# 4. WRITE BACK — push reconciled statuses / regenerated boards (one batch confirm)
python .claude/skills/activity-sync/writeback.py # git-signal corrections, or:
python scripts/generate_kanban.py --apply # plan-of-record → 3 platform kanbans
# 5. VERIFY LOCALLY (optional) — CI runs this anyway on push
python scripts/aggregator.py
(cd docs && LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 bundle exec jekyll serve)
```
The pushed `kanban.md` files fire each repo's `notify-kf-cpto.yml` dispatch → `aggregate.yml` rebuilds everything: unified kanban/calendar (sprint cadence, full timeline, per-sprint views), per-project pages (Planned-vs-Done pie, RAG sprint gantt), the Migration Gantt (`AUTO:migration-gantt` rendered live from `migration_plan.yml`), `loe.yml`/`gantt.yml`, GitHub Pages, and the Google Sheet.
**Reporting semantics (one story everywhere):**
- **Task names** carry `[F{faza}.S{sprint}.ShortName]` prefixes — faza and sprint readable at a glance.
- **Gantt bars are RAG by status:** grey Planned · amber In work · red Late/At-risk (past end date, or Todo past its start) · green Done. Legends render under every gantt; bar colours come from mermaid `themeVariables` in `docs/_layouts/default.html`.
- **Pies are Planned-vs-Done** (person-days) — portfolio-wide on the index, per project on each page.
- **Milestones** live in `docs/_data/calendar.yml`; the migration gantt and `gantt.yml` read them from there.
## How It Works
```mermaid
graph TD
subgraph repos["Tracked Project Repos"]
A["kf-platform/kanban.md<br/>MermaidJS Kanban"]
B["kf-fe-platform/kanban.md<br/>MermaidJS Kanban"]
C["kf-be-platform/kanban.md<br/>MermaidJS Kanban"]
D["R3-AAS/kanban.md<br/>MermaidJS Kanban"]
E["ai-rise-options/kanban.md<br/>MermaidJS Kanban"]
F["tech_brainstorming/kanban.md<br/>MermaidJS Kanban"]
end
A -->|push trigger| GHA
B -->|push trigger| GHA
C -->|push trigger| GHA
D -->|push trigger| GHA
E -->|push trigger| GHA
F -->|push trigger| GHA
subgraph GHA["GitHub Actions"]
DISC["discover.py<br/>GitHub API scan"]
AGG["aggregator.py<br/>parse + merge kanbans"]
CAL["Calendar + LOE<br/>effort + events"]
DISC --> AGG
AGG --> CAL
end
subgraph kfcpto["kf-cpto (Main Repo)"]
UK["unified-kanban.md<br/>Kanban Unificat"]
UC["unified-calendar.md<br/>Calendar + LOE"]
DG["dependency-graph.md<br/>Inter-project graph"]
PP["projects/*.md<br/>Per-project pages"]
end
AGG --> UK
AGG --> DG
AGG --> PP
CAL --> UC
UK --> PAGES
UC --> PAGES
DG --> PAGES
PP --> PAGES
PAGES["GitHub Pages<br/>Dashboard Echipa"]
PAGES --> GS["Google Sheets<br/>LOE Data"]
PAGES --> GC["Google Chat<br/>Notifications"]
```
### Data Flow
1. **A developer updates `kanban.md`** in their project repo and pushes
2. **`notify-kf-cpto.yml`** triggers a `repository_dispatch` event to kf-cpto
3. **`discover.py`** scans the GitHub org via API to find all repos with `kanban.md`
4. **`aggregate.yml`** clones discovered repos and runs the aggregation pipeline
5. **`aggregator.py`** parses all kanbans and generates unified views + dependency graph
6. **`sheets_sync.py`** pushes LOE data to Google Sheets
7. **GitHub Pages** deploys the dashboard
8. **Google Chat** receives a notification
## Knowledge Bundle (OKF) — Agent-Consumable Project Memory
Alongside the human dashboard, we emit an **[Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/tree/main/okf) (OKF v0.1)** bundle at [`docs/okf/`](docs/okf/) — a directory of cross-linked markdown + YAML-frontmatter "concept" files that any agent (or human) can read without bespoke parsing. It is generated by [`scripts/okf_export.py`](scripts/okf_export.py) as a **pure transform** of the data we have already parsed — it never re-reads `kanban.md` (the one-parser rule).
### What's in the bundle
| Concept | `type` | Built from |
| :--- | :--- | :--- |
| One file per tracked project | `Project` | parsed kanban + `loe.yml` rollup + `depends_on` cross-links + a delivery line read from each repo's GSD `.planning/STATE.md` |
| LOE and RAG-status definitions | `Metric` | canonical definitions, including the person-days vs working-day-span distinction |
| Migration milestones | `Milestone` | `docs/_data/calendar.yml` |
Plus OKF's reserved `index.md` (progressive-disclosure navigation) and `log.md` (change history). The bundle is Jekyll-excluded, so it ships as raw portable markdown, and it is **deterministic** — re-running the aggregator produces a byte-identical bundle (no run-timestamps in the bodies).
### Why we do this — the process value
- **[REUSE] One substrate for our agents.** The Activity Sync skill (and our Claude sessions) used to re-assemble context from scattered `kanban.md`, GSD `.planning/`, and the migration plan on every run. The OKF bundle is that context in one cross-linked place — exactly the "stop solving context-assembly from scratch" problem OKF was built for.
- **[SINGLE-SOURCE] The LOE metric is defined once.** Our recurring "is effort person-days or calendar span?" ambiguity now lives in a single `Metric` concept at [`docs/okf/metrics/loe.md`](docs/okf/metrics/loe.md) instead of tribal knowledge.
- **[BRIDGE] Board and delivery reality are linked as data.** Each project concept ties its migration tasks to its real GSD delivery state (milestone + percent), so the drift we reconcile every week is visible as machine-readable data, not just a manual judgment call.
- **[PORTABLE] No new dependency, no lock-in.** OKF is just markdown + frontmatter — we adopted the *format*, not a platform. There is **no Google Cloud or Knowledge Catalog dependency**; the bundle is readable by our own tools, the OKF reference visualizer, or any future consumer.
### What it is not
OKF is a **representation** layer, not a sync engine — it makes our knowledge legible and shareable, but reconciliation still lives in [`reconcile.py`](.claude/skills/activity-sync/reconcile.py) and [`generate_kanban.py`](scripts/generate_kanban.py). Conformance is enforced by [`scripts/validate_okf.py`](scripts/validate_okf.py), which runs **non-blocking** in CI: a malformed bundle is surfaced in the logs but is never allowed to block the canonical dashboard.
## Zero-Config Repo Registration
**No manual configuration needed.** To add a project to the dashboard:
1. Add a `kanban.md` file to your repo root (see format below)
2. Add the `.github/workflows/notify-kf-cpto.yml` workflow
3. Push — the dashboard discovers and includes your project automatically
### Quick Start with Templates
**Option A: Use GitHub Template Repo (Recommended)**
Create new project from template: [katty-fashion/project-template](https://github.com/katty-fashion/project-template) → **Use this template**
> **Important:** Always use **"Use this template"**, never **"Fork"**. Forks inherit the parent's visibility and cannot be made private independently. Templates create standalone repos with full control over visibility and settings.
New repos automatically include:
- `kanban.md` with correct format
- `.github/workflows/notify-kf-cpto.yml` for auto-sync
- `README.md` with architecture documentation
After creating, update `kanban.md` frontmatter: set `project:` to your repo name and fill in the other fields.
**Option B: Manual Setup**
```bash
# From your project repo root
curl -sL https://raw.githubusercontent.com/katty-fashion/kf-cpto/master/templates/kanban.md -o kanban.md
curl -sL https://raw.githubusercontent.com/katty-fashion/kf-cpto/master/templates/REPO_README.md -o README.md
mkdir -p .github/workflows
curl -sL https://raw.githubusercontent.com/katty-fashion/kf-cpto/master/templates/.github/workflows/notify-kf-cpto.yml -o .github/workflows/notify-kf-cpto.yml
```
## Kanban Format
Each project's `kanban.md` is the **single source of truth** — it seeds the dashboard with all project data.
```yaml
---
project: your-project-name
description: "Short project description"
type: saas # saas | eu-project | internal
po: "@product-owner"
lead: "@tech-lead"
sprint: S3
sprint_start: 2026-03-02
sprint_end: 2026-03-13
depends_on: [nuoform] # other project names this depends on
tags: [frontend, mvp] # free-form tags
team: # optional — used by the kanban generator for assignee mapping
frontend: dev.fe@katty-fashion.ro
backend: dev.be@katty-fashion.ro
---
# Project Kanban
| Task | Assignee | Effort | Start | End | Status |
| :--- | :--- | :--- | :--- | :--- | :--- |
| Implement feature X | @developer | 3d | 2026-03-02 | 2026-03-04 | In Progress |
| Code review for Y | @reviewer | 1d | 2026-03-05 | 2026-03-05 | Review |
| Deploy to staging | @devops | 2d | | | Todo |
```
The **6-column** form (with `Start`/`End`) is recommended — the dates drive the per-project Gantt. The legacy **4-column** form (`| Task | Assignee | Effort | Status |`) is still supported.
### Frontmatter Fields
| Field | Required | Description |
| :--- | :---: | :--- |
| `project` | Yes | Repo name (must match GitHub repo) |
| `description` | No | Short description shown on dashboard cards |
| `type` | No | `saas`, `eu-project`, or `internal` (default) |
| `po` | No | Product owner contact |
| `lead` | No | Technical lead contact |
| `sprint` | Yes | Sprint identifier (S1, S2...) |
| `sprint_start` | Yes | Sprint start date (YYYY-MM-DD) |
| `sprint_end` | Yes | Sprint end date (YYYY-MM-DD) |
| `depends_on` | No | List of project names this depends on (powers the dependency graph) |
| `tags` | No | Free-form tags for categorization |
| `team` | No | `frontend` / `backend` / `tech_lead` emails — used by the kanban generator to derive assignees |
### Task Table
| Column | Format | Valid Values |
| :--- | :--- | :--- |
| Task | Free text | Task description |
| Assignee | `@username` | One or more `@handles` (e.g. `@fe + @be`) |
| Effort | `Nd` | Number + 'd' for **person-days** (e.g., `3d`, `0.5d`) |
| Start | `YYYY-MM-DD` | Optional — start date (drives the Gantt) |
| End | `YYYY-MM-DD` | Optional — end date (drives the Gantt) |
| Status | Canonical | `Todo`, `In Progress`, `Review`, `Done` |
**Parsing is forgiving.** The parser maps columns by **header name**, so an `Owner` column is read as Assignee and a `Deadline` column as End; tables without a `Task` column (e.g. summary tables) are skipped. Statuses are **canonicalized** — `In progress`, emoji-prefixed (`🔄 In Progress`), and common synonyms are normalized to the four canonical values; anything unrecognized is left as-is with a warning.
### Status Color Indicators
The aggregator automatically adds colored left borders to kanban cards based on task status:
| Status | Color | MermaidJS Priority |
| :--- | :--- | :--- |
| In Progress | Red | `Very High` |
| Review | Orange | `High` |
| Todo | Blue | `Low` |
| Done | Default | — |
Assignees are also shown on each card via the `assigned` metadata.
## Automation Workflows
### Primary: Unified Sync (`aggregate.yml`)
| Trigger | When |
| :--- | :--- |
| Push to master | Immediate |
| Repository dispatch | When any project updates its kanban |
| Schedule | Monday 04:00 UTC |
| Manual | workflow_dispatch |
**Pipeline steps:**
1. `discover.py` — Scan GitHub org for repos with `kanban.md`
2. Clone all discovered repos
3. `aggregator.py` — Generate unified-kanban, calendar, LOE report, dependency graph, project pages
4. `sheets_sync.py` — Sync LOE data to Google Sheets
5. Commit and push updated docs
6. Deploy to GitHub Pages
7. Notify Google Chat
### Secondary: Sheets Sync (`sync_to_sheets.yml`)
| Trigger | When |
| :--- | :--- |
| Schedule | Weekdays 09:00 UTC |
| Manual | workflow_dispatch |
Lightweight — discovers repos, syncs LOE data to Google Sheets only.
### Per-Repo: Notify (`notify-kf-cpto.yml`)
Installed in each project repo. Triggers on push to `kanban.md` and sends a `repository_dispatch` event to kf-cpto.
## Configuration
### Required GitHub Secrets
| Secret | Level | Purpose |
| :--- | :--- | :--- |
| `KF_PAT` | **Org** | Cross-repo dispatch + cloning (needed by kf-cpto and every project repo) |
| `GOOGLE_CHAT_WEBHOOK` | **Org** | Dashboard update notifications |
| `GSHEET_ID` | **Repo** (kf-cpto) | Google Sheet ID for LOE sync |
| `GSHEET_SUMMARY_ID` | **Repo** (kf-cpto) | SEPARATE R3Group spreadsheet for the cross-project Summary tab; defaults to the R3Group sheet id when unset. The sheet must be shared (Editor) with `GSHEET_CLIENT_EMAIL`. |
| `GSHEET_CLIENT_EMAIL` | **Repo** (kf-cpto) | Service account email |
| `GSHEET_PRIVATE_KEY` | **Repo** (kf-cpto) | Service account private key |
| `GITHUB_TOKEN` | **Auto** | Provided by GitHub Actions |
### Setting Up GitHub PAT (Organization Secret)
1. **GitHub → Settings → Developer Settings → Personal Access Tokens → Fine-grained tokens**
2. **Name:** `kf-cpto-sync`, **Expiration:** 90 days
3. **Repository access:** All repositories (or select katty-fashion repos)
4. **Permissions:** Contents (Read-only), Metadata (Read-only) — for CI discovery/cloning. **Note:** the local `activity-sync` write-back step needs **Contents: Read and Write** (plus Pull requests: Read to mine merged PRs); use a token with write access when running `writeback.py`.
5. **Add as Org Secret:** `github.com/katty-fashion → Settings → Secrets → Actions → New organization secret`
### Setting Up Google Sheets
1. Enable **Google Sheets API** in [Google Cloud Console](https://console.cloud.google.com)
2. Create **Service Account** → Download JSON key
3. Create Google Sheet → Share with service account email (Editor) → Create **LOE** tab
4. Add secrets: `GSHEET_ID`, `GSHEET_CLIENT_EMAIL`, `GSHEET_PRIVATE_KEY`
### Setting Up Google Chat
1. Open Chat space → **Manage webhooks** → Create webhook
2. Add `GOOGLE_CHAT_WEBHOOK` as org secret
## Local Development
```bash
# Clone
git clone https://github.com/katty-fashion/kf-cpto.git
cd kf-cpto
# Discover and clone project repos
export KF_PAT=your-token
uv run --with pyyaml --with requests scripts/discover.py
while read repo; do
git clone --depth=1 https://github.com/katty-fashion/${repo}.git repos/${repo}
done < repos/discovered.txt
# Run aggregator
uv run --with pyyaml scripts/aggregator.py
# Run sheets sync (dry-run without credentials)
uv run --with pyyaml scripts/sheets_sync.py
# Serve docs locally
cd docs && bundle exec jekyll serve
```
## File Structure
```
kf-cpto/
├── .claude/skills/activity-sync/ # Local Claude skill — activity-driven reconciliation
│ ├── SKILL.md # Skill reference (commands, output, recovery)
│ ├── bootstrap.py # First-run: clone tracked repos + seed markers
│ ├── repo_enum.py # Enumerate + fetch + parse tracked repos (read-only)
│ ├── reconcile.py # Mine git activity → propose status changes (dry-run)
│ ├── writeback.py # Sanitize + write + push corrected kanban.md
│ └── sanitize.py # Mermaid-breaking-character sanitization
├── .github/workflows/
│ ├── aggregate.yml # Primary workflow — full sync pipeline
│ └── sync_to_sheets.yml # Secondary workflow — LOE sync only
├── docs/
│ ├── _config.yml # Jekyll configuration
│ ├── _layouts/default.html # Layout with Pico CSS + MermaidJS
│ ├── _includes/
│ │ ├── sidebar.html # Dynamic navigation (from projects collection)
│ │ └── card.html # Card component
│ ├── _data/
│ │ ├── calendar.yml # Migration calendar config (hand-edited)
│ │ ├── migration_plan.yml # Migration plan-of-record (source for the generator)
│ │ ├── gantt.yml # Gantt rows parsed from migration-gantt.md (auto)
│ │ ├── loe.yml # Canonical LOE intermediate (auto)
│ │ └── sync_status.yml # Aggregator + Sheets health (auto)
│ ├── index.md # Dashboard homepage (dynamic project cards)
│ ├── unified-kanban.md # Aggregated kanban (auto-generated)
│ ├── unified-calendar.md # Sprint calendar (auto-generated)
│ ├── migration-gantt.md # Migration Gantt (prose + AUTO blocks)
│ ├── loe-report.md # LOE report (auto-generated)
│ ├── dependency-graph.md # Inter-project graph (auto-generated)
│ └── _projects/ # Per-project pages (Jekyll collection, auto-generated)
├── scripts/
│ ├── discover.py # GitHub API repo discovery
│ ├── aggregator.py # Main aggregation + generation
│ ├── generate_kanban.py # Split the migration plan-of-record into per-repo kanbans
│ ├── auto_blocks.py # Render idempotent AUTO:* blocks in augmented pages
│ ├── validate_auto_blocks.py # CI lint for AUTO markers
│ ├── sheets_sync.py # Google Sheets LOE sync
│ ├── utils.py # Shared utilities (canonical kanban parser)
│ └── test_generate_kanban.py # Unit tests (parser, canonicalization, generator)
├── templates/ # Starter templates for new project repos
│ ├── kanban.md # Kanban template with full frontmatter
│ ├── REPO_README.md # README template with architecture docs
│ └── .github/workflows/
│ └── notify-kf-cpto.yml # Auto-sync dispatch workflow
└── README.md
```
## Troubleshooting
| Issue | Solution |
| :--- | :--- |
| Project not appearing on dashboard | Ensure `kanban.md` exists at repo root (not in a subdirectory) |
| Task shows an odd status | Statuses are canonicalized; an unrecognized value is left as-is with a `Warning:` in the aggregator log — fix it to one of `Todo`, `In Progress`, `Review`, `Done` |
| Effort not calculated | Format: `Nd` (e.g., `3d`, `1.5d`, `0.5d`) |
| Generator logs `[CONFLICT]` for a repo | The local clone diverged or its `kanban.md` changed on origin — `git -C repos-local/<repo> status` and resolve, then re-run |
| Dispatch not triggering | Verify event type is `kanban-updated` in notify workflow |
| Sheets empty | Check `GSHEET_ID`, `GSHEET_CLIENT_EMAIL`, `GSHEET_PRIVATE_KEY` secrets are set |
| Discovery finds no repos | Ensure `KF_PAT` has read access to org repos |
| `aggregate.yml` run fails on "Commit unified docs" | Harmless push race when several repos dispatch at once — the next run commits the docs. (No `concurrency:` guard yet.) |
## Tools Under Evaluation
| Tool | Purpose | Link |
| :--- | :--- | :--- |
| **Dockwatch** | Docker container management — Web UI for per-container update scheduling, cron-based updates, multi-platform notifications (Slack, Discord, email). Potential to greatly simplify container update workflows vs manual `docker pull`/`compose up` cycles. | [Wiki](https://dockwatch.wiki/) · [GitHub](https://github.com/Notifiarr/dockwatch) |
---
*KF Team — Git-Native Project Management*
``