diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index d55ce87d..3fd3c9e7 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -65,6 +65,90 @@ should include: Images should be hosted with GitHub user attachments or another external asset URL instead of committed to the repository. +## Fork-as-Lab Workflow + +`Fearvox/EverOS` is a development fork of `EverMind-AI/EverOS`. All experimental +work happens on the fork before selective promotion upstream. + +### Staying Current with Upstream + +The fork auto-rebases onto upstream `main` every 6 hours via +`sync-upstream.yml`. This replays fork-only commits (templates, workflows, docs) +on top of the latest upstream. If you're working on a feature branch: + +```bash +# Rebase your branch onto the latest fork main +git fetch origin +git rebase origin/main +``` + +If the auto-rebase encounters a conflict, it aborts and opens a tracking issue. +Manual resolution: + +```bash +git checkout main +git pull upstream main --rebase +# resolve conflicts, then: +git push origin main --force-with-lease +``` + +### Branch Strategy + +| Branch pattern | Purpose | Lifetime | +|---------------|---------|----------| +| `sleep-iter-*-*` | Automated overnight runs | Feature branch, merged or closed | +| `codex-watch-*` | Codex co-agent patrol | Isolated worktree, never touch | +| `feature/*` | Human-driven features | Feature branch -> PR to origin/main | +| `sleep-log` | Overnight run audit log | Persistent tracking branch | + +### Label Conventions + +| Label | Color | Use on | +|-------|-------|--------| +| `pr-mirror` | `#0E8A16` | Issues that mirror an upstream PR; triggers Linear sync | +| `tracking` | `#5319E7` | Long-lived tracking issues | +| `security` | `#B60205` | Security advisories or security-relevant PRs | +| `urgent` | `#D93F0B` | High-priority; escalates in Linear | +| `sync-failed` | `#D93F0B` | Auto-applied when Linear sync fails for an issue | + +### Issue Templates + +Use the template picker when opening an issue. The two fork-specific templates: + +- **PR Tracker** (`pr_tracker.yml`) tracks an upstream PR for Linear/Slack + visibility. Requires `pr_number`, `pr_url`, `author`, `area`, `scope`, and + `evidence`. Applies `pr-mirror` and `tracking` labels. +- **Security Tracker** (`security_tracker.yml`) tracks a security advisory. + Adds `security` and `urgent` labels on top of the PR tracker labelset. + +Both templates auto-trigger `linear-sync.yml`, which creates a corresponding +Linear issue in the `EverMind-Dash` project and comments back with the EVE +identifier. + +### Linear Sync + +Issues labeled `pr-mirror` are mirrored to Linear's `EverMind-Dash` project +automatically. The sync is one-way from GitHub to Linear. The bot comments back +with the matching EVE issue identifier on success. + +If the bot adds a `sync-failed` label, check the workflow run logs at +`https://github.com/Fearvox/EverOS/actions/workflows/linear-sync.yml`. + +### Promoting to Upstream + +When a fork change is ready for `EverMind-AI/EverOS`: + +```bash +gh pr create --repo EverMind-AI/EverOS \ + --base main \ + --head Fearvox:main \ + --title "feat: description" --body "..." +``` + +Templates and workflows committed to the fork are replayed on top of upstream +during every rebase cycle. They never conflict unless upstream adds same-named +files, which is handled by auto-rebase conflict detection. + ## Style Notes - Follow existing patterns before adding new abstractions. diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index aa74ce5f..cb06530f 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -19,6 +19,63 @@ permissions: contents: read jobs: + markdown-lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Collect changed Markdown files + id: changed-markdown + env: + EVENT_NAME: ${{ github.event_name }} + BASE_REF: ${{ github.base_ref }} + BEFORE_SHA: ${{ github.event.before }} + AFTER_SHA: ${{ github.sha }} + run: | + python3 - <<'PY' >> "$GITHUB_OUTPUT" + from pathlib import Path + import os + import subprocess + + event_name = os.environ["EVENT_NAME"] + if event_name == "pull_request": + base_ref = os.environ["BASE_REF"] + subprocess.run(["git", "fetch", "origin", base_ref, "--depth=1"], check=True) + diff_range = f"origin/{base_ref}...HEAD" + else: + before = os.environ.get("BEFORE_SHA", "") + after = os.environ["AFTER_SHA"] + if before and set(before) != {"0"}: + diff_range = f"{before}..{after}" + else: + diff_range = f"{after}^..{after}" + + result = subprocess.run( + ["git", "diff", "--name-only", "--diff-filter=ACMRT", diff_range], + check=True, + text=True, + stdout=subprocess.PIPE, + ) + files = [ + path + for path in result.stdout.splitlines() + if path.endswith(".md") and Path(path).is_file() + ] + + print("files<