diff --git a/.githooks/post-checkout b/.githooks/post-checkout index 573833dd..71e65b25 100755 --- a/.githooks/post-checkout +++ b/.githooks/post-checkout @@ -5,4 +5,4 @@ repo_root="$({ cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd })" -"$repo_root/scripts/ensure_agent_hardlinks.sh" >/dev/null +"$repo_root/scripts/ensure_agent_hardlinks.sh" --quiet diff --git a/.githooks/post-merge b/.githooks/post-merge index 573833dd..71e65b25 100755 --- a/.githooks/post-merge +++ b/.githooks/post-merge @@ -5,4 +5,4 @@ repo_root="$({ cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd })" -"$repo_root/scripts/ensure_agent_hardlinks.sh" >/dev/null +"$repo_root/scripts/ensure_agent_hardlinks.sh" --quiet diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 61cb6e0b..2fbb72c1 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -183,7 +183,7 @@ See [CI Architecture](docs/dev/CI/architecture.md) for full details. |------|--------|-----| | `cargo fmt`, `cargo clippy` | GitHub-hosted | Fast, parallel, free | | `cargo audit`, `cargo deny` | GitHub-hosted | Security checks, no build needed | -| `cargo build` | **Self-hosted** | Warm cache, THE build | +| `cargo build`, `cargo test --workspace` | GitHub-hosted | Fast cores; no hardware needed | | Hardware tests | **Self-hosted** | Requires display/audio/clipboard | ### DON'T (Common AI Mistakes) diff --git a/.github/workflows/docs-ci.yml b/.github/workflows/docs-ci.yml index 3a407d50..e9c69403 100644 --- a/.github/workflows/docs-ci.yml +++ b/.github/workflows/docs-ci.yml @@ -41,8 +41,16 @@ jobs: - name: Validate agent instruction mirrors run: | - diff -u AGENTS.md .github/copilot-instructions.md - diff -u AGENTS.md .kilocode/rules/agents.md + if ! diff -u AGENTS.md .github/copilot-instructions.md; then + echo "::error::Agent instruction mirror drift: .github/copilot-instructions.md differs from AGENTS.md" + echo "hint: run ./scripts/ensure_agent_hardlinks.sh (or mise run prepare)" >&2 + exit 1 + fi + if ! diff -u AGENTS.md .kilocode/rules/agents.md; then + echo "::error::Agent instruction mirror drift: .kilocode/rules/agents.md differs from AGENTS.md" + echo "hint: run ./scripts/ensure_agent_hardlinks.sh (or mise run prepare)" >&2 + exit 1 + fi - name: Append revision log entries run: | diff --git a/.kilocode/rules/agents.md b/.kilocode/rules/agents.md index 61cb6e0b..2fbb72c1 100644 --- a/.kilocode/rules/agents.md +++ b/.kilocode/rules/agents.md @@ -183,7 +183,7 @@ See [CI Architecture](docs/dev/CI/architecture.md) for full details. |------|--------|-----| | `cargo fmt`, `cargo clippy` | GitHub-hosted | Fast, parallel, free | | `cargo audit`, `cargo deny` | GitHub-hosted | Security checks, no build needed | -| `cargo build` | **Self-hosted** | Warm cache, THE build | +| `cargo build`, `cargo test --workspace` | GitHub-hosted | Fast cores; no hardware needed | | Hardware tests | **Self-hosted** | Requires display/audio/clipboard | ### DON'T (Common AI Mistakes) diff --git a/AGENTS.md b/AGENTS.md index 61cb6e0b..2fbb72c1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -183,7 +183,7 @@ See [CI Architecture](docs/dev/CI/architecture.md) for full details. |------|--------|-----| | `cargo fmt`, `cargo clippy` | GitHub-hosted | Fast, parallel, free | | `cargo audit`, `cargo deny` | GitHub-hosted | Security checks, no build needed | -| `cargo build` | **Self-hosted** | Warm cache, THE build | +| `cargo build`, `cargo test --workspace` | GitHub-hosted | Fast cores; no hardware needed | | Hardware tests | **Self-hosted** | Requires display/audio/clipboard | ### DON'T (Common AI Mistakes) diff --git a/README.md b/README.md index a20604e1..8a3816e9 100644 --- a/README.md +++ b/README.md @@ -1,116 +1,29 @@ -# ColdVox -> ⚠️ **Internal Alpha** - This project is in early development and not ready for production use. - -> **⚠️ CRITICAL**: Documentation is out of sync with code. Whisper STT has been removed; Parakeet doesn't compile. See [`docs/plans/critical-action-plan.md`](docs/plans/critical-action-plan.md) for current status. **Only Moonshine STT works** (requires `uv sync` first). -## Development - - Install Rust (stable) and required system dependencies for your platform. - - Use the provided scripts in `scripts/` to help with local environment setup. - -### Developer Git Hooks - -This project uses a "Zero-Latency" git hook standard powered by **[mise](https://mise.jdx.dev)** and **lint-staged**. - -### Setup -1. **Install mise**: `curl https://mise.run | sh` (or see [docs](https://mise.jdx.dev/getting-started.html)) -2. **Install dependencies**: `mise install` -3. **Activate hooks**: `mise run prepare` (runs automatically on `npm install`) - -Hooks will now run automatically on `git commit`. To run manually: -```bash -mise run pre-commit -``` - # ColdVox > ⚠️ **Internal Alpha** - This project is in early development and not ready for production use. -Minimal root README. Full developer & architecture guide: see [`CLAUDE.md`](CLAUDE.md). - -## Overview -ColdVox is a modular Rust workspace providing real‑time audio capture, VAD, STT (Faster-Whisper), and cross‑platform text injection. +> **⚠️ CRITICAL**: Documentation and feature status changes quickly. See [`docs/plans/critical-action-plan.md`](docs/plans/critical-action-plan.md) for what currently works. -## Quick Start +Minimal root README. Full developer & architecture guide: see [`CLAUDE.md`](CLAUDE.md). Assistants should read [`AGENTS.md`](AGENTS.md). -**For Voice Dictation (Recommended):** -```bash -# Run with default Faster-Whisper STT and text injection (model auto-discovered) -cargo run --features text-injection - -# With specific microphone device -cargo run --features text-injection -- --device "HyperX QuadCast" - -# TUI Dashboard with controls -cargo run --bin tui_dashboard --features tui -``` - -**Other Usage:** -```bash -# VAD-only mode (no speech recognition) -cargo run - -# Test microphone setup -cargo run --bin mic_probe -- list-devices -``` - -> Audio dumps: The TUI dashboard now records raw audio to `logs/audio_dumps/` by default. Pass `--dump-audio=false` to disable persistent capture. - -**Note on Defaults**: Faster-Whisper STT is the default feature (enabled automatically), ensuring real speech recognition in the app and tests. This prevents fallback to the mock plugin, which skips transcription. Override with `--stt-preferred mock` or env `COLDVOX_STT_PREFERRED=mock` if needed for testing. For other STT backends, enable their features and set preferred accordingly. - -### Configuration (Canonical Path) -- Canonical STT selection config lives at `config/plugins.json`. -- Any legacy duplicates like `./plugins.json` or `crates/app/plugins.json` are deprecated and ignored at runtime. A warning is logged on startup if they exist. Please migrate changes into `config/plugins.json` only. -- Some defaults can also be set in `config/default.toml`, but `config/plugins.json` is the source of truth for STT plugin selection. - -### Whisper Model Setup -- **Python Package**: Install the `faster-whisper` Python package via pip -- **Models**: Whisper models are automatically downloaded on first use -- **Model Identifiers**: Use standard Whisper model names (e.g., "tiny.en", "base.en", "small.en", "medium.en") -- **Manual Path**: Set `WHISPER_MODEL_PATH` to specify a model identifier or custom model directory -- **Common Models**: - - "tiny.en" (~39MB) - Fastest, lower accuracy - - "base.en" (~142MB) - Good balance of speed and accuracy - - "small.en" (~466MB) - Better accuracy - - "medium.en" (~1.5GB) - High accuracy - -## How It Works -1. **Always-on pipeline**: Audio capture, VAD, STT, and text-injection buffering run continuously by default. Raw 16 kHz mono audio is recorded to `logs/audio_dumps/` for later review. -2. **Voice activation (default)**: The Silero VAD segments speech automatically—no hotkey required. -3. **Push-to-talk (preview inject)**: Hold `Super+Ctrl` to stream buffered text into the preview/injection window when you need manual control. Release to stop feeding new text. - -More detail: See [`CLAUDE.md`](CLAUDE.md) for full developer guide. - -### Python 3.13 and PyO3 -If your system default Python is 3.13, current `pyo3` versions may warn about unsupported Python version during build. Two options: +## Development -1) Prefer Python 3.12 for development tools, or -2) Build using the stable Python ABI by exporting: +### Developer Git Hooks -```bash -set -gx PYO3_USE_ABI3_FORWARD_COMPATIBILITY 1 # fish shell -cargo check -``` +This project uses a git hook standard powered by **[mise](https://mise.jdx.dev)** and **lint-staged**. -We plan to upgrade `pyo3` in a follow-up to remove this requirement. +1. Install mise: `curl https://mise.run | sh` (or see [docs](https://mise.jdx.dev/getting-started.html)) +2. Install toolchain: `mise install` +3. Activate hooks + agent mirrors: `mise run prepare` -### Future Vision (Experimental) -- We're actively exploring an **always-on intelligent listening** architecture that keeps a lightweight listener running continuously and spins up tiered STT engines on demand. -- This speculative work includes decoupled listening/processing threads, dynamic STT memory management, and context-aware activation. -- Read the full experimental plan in [`docs/architecture.md`](docs/architecture.md#coldvox-future-vision). Treat it as research guidance—not a committed roadmap. +To run the hook pipeline manually: -## Slow / Environment-Sensitive Tests -Some end‑to‑end tests exercise real injection & STT. Gate them locally by setting an env variable (planned): ```bash -export COLDVOX_SLOW_TESTS=1 -cargo test -- --ignored +mise run pre-commit ``` -Headless behavior notes: see [`docs/text_injection_headless.md`](docs/text_injection_headless.md). - -## License -Dual-licensed under MIT or Apache-2.0. See `LICENSE-MIT` and `LICENSE-APACHE` if present, else crate-level manifests. ## Contributing - Review the [Master Documentation Playbook](docs/MasterDocumentationPlaybook.md). - Follow the repository [Documentation Standards](docs/standards.md). - Coordinate work through the [Documentation Todo Backlog](docs/todo.md). -- Assistants should read [`AGENTS.md`](AGENTS.md). diff --git a/docs/MasterDocumentationPlaybook.md b/docs/MasterDocumentationPlaybook.md index a1bbaf4d..8c943274 100644 --- a/docs/MasterDocumentationPlaybook.md +++ b/docs/MasterDocumentationPlaybook.md @@ -93,13 +93,13 @@ The following files configure AI coding agents and MUST live at standard locatio - `AGENTS.md` (root): Canonical agent instructions following the [AGENTS.md standard](https://agents.md/). This is the single source of truth for all AI agents. - `CLAUDE.md` (root): Claude Code configuration. Should import from or reference `AGENTS.md`. -- `.github/copilot-instructions.md`: GitHub Copilot instructions. Symlink to `AGENTS.md`. -- `.kilocode/rules/agents.md`: Kilo Code rules. Symlink to `../../AGENTS.md`. +- `.github/copilot-instructions.md`: GitHub Copilot instructions. Must match `AGENTS.md` (locally hardlinked where possible). +- `.kilocode/rules/agents.md`: Kilo Code rules. Must match `AGENTS.md` (locally hardlinked where possible). - `.gemini/settings.json`: Gemini CLI configuration. Set `"contextFileName": "AGENTS.md"` to use root AGENTS.md. - `.cursorrules` (root, optional): Cursor-specific rules if needed beyond `AGENTS.md`. - `.builderrules` (root, optional): Builder.io-specific rules if needed. -**Hierarchy**: `AGENTS.md` is authoritative. Tool-specific files should either symlink to it or contain only tool-specific overrides that reference `AGENTS.md`. +**Hierarchy**: `AGENTS.md` is authoritative. Tool-specific files should either be hardlinked mirrors (preferred) or contain only tool-specific overrides that reference `AGENTS.md`. **Do NOT create** `docs/agents.md` - agent configuration lives at the root for tool discovery. diff --git a/docs/dev/CI/architecture.md b/docs/dev/CI/architecture.md index 03a2e1b2..3cabf40c 100644 --- a/docs/dev/CI/architecture.md +++ b/docs/dev/CI/architecture.md @@ -6,52 +6,43 @@ ColdVox CI splits workloads between GitHub-hosted and self-hosted runners based on one question: -**Does this task require the physical laptop's hardware?** +**Does this task require the physical laptop's hardware (display, audio, clipboard)?** | Requires Laptop? | Task | Runner | |------------------|------|--------| | No | `cargo fmt --check` | GitHub-hosted | | No | `cargo clippy` | GitHub-hosted | | No | `cargo audit`, `cargo deny` | GitHub-hosted | -| **Yes** | `cargo build` (warm cache) | Self-hosted | +| No | `cargo build` | GitHub-hosted | +| No | `cargo test --workspace` (unit tests) | GitHub-hosted | | **Yes** | Hardware tests (display, audio, clipboard) | Self-hosted | --- ## Why Split? -### 1. CPU Dedication +### 1. Hardware Isolation -If the laptop runs lint, build, AND tests sequentially, they compete for CPU. +The self-hosted runner is a laptop with **weak hardware but a live display**. GitHub-hosted runners have **powerful hardware but no display**. -With the split: -- **Laptop**: 100% CPU on building + hardware tests -- **GitHub**: Handles lint/security on their infrastructure (free) +- **Laptop**: Only runs tests that need real display/audio/clipboard +- **GitHub**: Handles everything else (lint, security, build, unit tests) -### 2. No Redundant Builds - -| Bad Pattern | Good Pattern | -|-------------|--------------| -| GitHub: `cargo build` (discarded) | GitHub: `cargo clippy` (type checks only) | -| Self-hosted: `cargo build` (again) | Self-hosted: `cargo build` (THE build) | - -`clippy` does full type checking without generating binaries. Same error detection, no wasted compilation. - -### 3. Parallelism +### 2. Parallelism GitHub-hosted jobs run in parallel on separate machines. Self-hosted queues on one laptop. ``` Push PR: - GitHub: [lint] [security] [docs] ← All parallel, 2 min each - Self-hosted: [build + hardware tests] ← Starts immediately, 8-12 min + GitHub: [lint] [security] [docs] [build+unit-tests] ← All parallel + Self-hosted: [hardware tests] ← Only hardware-dependent tests -Total time: ~12 min (not 2 + 2 + 2 + 12 = 18 min) +Total time: max(GitHub jobs, hardware tests) ``` -### 4. No Waiting +### 3. No Wasted Work -Self-hosted has **no `needs:` dependency**. It starts immediately in parallel with GitHub-hosted jobs. +The laptop does minimal work - just the tests that *require* hardware access. --- @@ -74,8 +65,8 @@ Self-hosted has **no `needs:` dependency**. It starts immediately in parallel wi | `GabrielBB/xvfb-action` | Internally calls `apt-get` (doesn't exist) | | `sudo apt-get install` | Wrong package manager | | `DISPLAY=:99` | Conflicts with real display (`:0`) | -| `needs: [lint, build]` | Delays self-hosted start by 5-10 min | -| `cargo build` on GitHub-hosted | Wasted work (can't share artifacts with Fedora) | +| Running builds on self-hosted | Weak hardware; GitHub-hosted is faster | +| Running unit tests on self-hosted | Wastes limited resources | --- @@ -84,41 +75,45 @@ Self-hosted has **no `needs:` dependency**. It starts immediately in parallel wi ``` ┌─────────────────────────────────────────────────────────────────┐ │ GITHUB-HOSTED (ubuntu-latest) │ -│ Parallel, free, NO BUILD artifacts │ +│ Parallel, powerful, handles most work │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ lint │ │ security │ │ docs │ │ -│ │ │ │ │ │ (optional) │ │ +│ │ │ │ │ │ │ │ │ │ fmt --check │ │ cargo audit │ │ cargo doc │ │ │ │ clippy │ │ cargo deny │ │ │ │ -│ │ │ │ │ │ │ │ │ │ ~2 min │ │ ~2 min │ │ ~2 min │ │ -│ │ NO BUILD │ │ NO BUILD │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ build_and_unit_tests │ │ +│ │ cargo check → cargo build → cargo test --workspace │ │ +│ │ ~10-15 min │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ └─────────────────────────────────────────────────────────────────┘ - ║ ║ - ║ (parallel, no waiting) ║ - ║ ║ + ║ + ║ (parallel, no waiting) + ║ ┌─────────────────────────────────────────────────────────────────┐ │ SELF-HOSTED (Fedora/Nobara) │ -│ Live KDE Plasma - THE build, THE tests │ +│ Weak hardware BUT has live KDE Plasma display │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ -│ │ hardware │ │ +│ │ hardware_tests │ │ │ │ │ │ │ │ Environment: │ │ -│ │ • DISPLAY=$DISPLAY (from session, NOT :99) │ │ -│ │ • WAYLAND_DISPLAY=$WAYLAND_DISPLAY │ │ +│ │ • DISPLAY=:0 (live session, NOT :99) │ │ +│ │ • WAYLAND_DISPLAY=wayland-0 │ │ │ │ • Real audio, real clipboard │ │ │ │ │ │ -│ │ Steps: │ │ -│ │ 1. cargo build (incremental, sccache, mold) → 2-3 min │ │ -│ │ 2. Hardware tests (injection, audio) → 5-8 min │ │ +│ │ Tests: │ │ +│ │ • real-injection-tests (xdotool, ydotool, clipboard) │ │ +│ │ • hardware_check (audio capture, display access) │ │ │ │ │ │ -│ │ Total: ~8-12 min │ │ +│ │ Total: ~5-10 min (minimal work!) │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ diff --git a/docs/plans/documentation-migration-mapping.md b/docs/plans/documentation-migration-mapping.md index 6eb0b041..a80310eb 100644 --- a/docs/plans/documentation-migration-mapping.md +++ b/docs/plans/documentation-migration-mapping.md @@ -9,6 +9,11 @@ last_reviewed: 2025-10-19 # Documentation Migration Mapping +> **Note (current-state override)**: This plan predates the current agent-instruction policy. +> `AGENTS.md` at the repo root is the canonical agent instruction file. +> Tool-specific entrypoints (`.github/copilot-instructions.md`, `.kilocode/rules/agents.md`) are kept in sync with `AGENTS.md` (and are locally hardlinked where possible). +> **Do not create** `docs/agents.md`. + This plan catalogs existing Markdown files and maps each one to the canonical target location (or disposition) required by the Master Documentation Playbook v1.0.0. The mapping will guide the relocation work in Phase 3 and ensures no markdown remains outside `/docs` except approved exceptions. ## Status Update @@ -47,7 +52,7 @@ Phase 1 and the majority of Phase 2–3 migrations have been executed. Remaining | .github/prompts/FileInventory.prompt.md | docs/research/logs/file-inventory-prompt.md | move | Add retention banner (ephemeral). | | .github/SETUP_RELEASE_TOKEN.md | docs/repo/setup-release-token.md | move | Add frontmatter; categorize under repo meta. | | CHANGELOG.md | CHANGELOG.md | retain-exception | Approved root exception. Add reference to docs/standards.md exceptions. | -| CLAUDE.md | CLAUDE.md | retain-exception | Must mirror docs/agents.md post-migration. | +| CLAUDE.md | CLAUDE.md | retain-exception | Must reference/import `AGENTS.md` (canonical). | | README.md | README.md | retain-exception | Update contributing links to new docs. | ## Inside `/docs` @@ -128,7 +133,7 @@ Phase 1 and the majority of Phase 2–3 migrations have been executed. Remaining ## Required New Files/Stubs - docs/standards.md — Document metadata schema, approved exceptions, changelog rubric, watcher spec. -- docs/agents.md — Assistant interaction index mirrored by CLAUDE.md. +- (Removed) `docs/agents.md` — superseded by root `AGENTS.md`. - docs/dependencies.md — Dependency overview. - docs/repo/gitignore.md — Explain .gitignore conventions. - docs/repo/editor.md — Editor/IDE guidelines. diff --git a/docs/plans/documentation/future-documentation-architecture.md b/docs/plans/documentation/future-documentation-architecture.md index 8cbd387a..768f9936 100644 --- a/docs/plans/documentation/future-documentation-architecture.md +++ b/docs/plans/documentation/future-documentation-architecture.md @@ -9,6 +9,10 @@ last_reviewed: 2025-10-19 # Future Documentation Architecture +> **Note (current-state override)**: Agent instructions are canonical in `AGENTS.md` at the repo root. +> Tool-specific entrypoints (e.g. `.github/copilot-instructions.md`, `.kilocode/rules/agents.md`) must mirror `AGENTS.md`. +> **Do not create** `docs/agents.md`. + ## Overview This document describes the future state of ColdVox documentation architecture, based on the comprehensive restructure proposal in `docs/proposal_documentation_restructure.md`. The goal is to transform our current scattered documentation into a well-organized, maintainable, and discoverable knowledge base. @@ -45,7 +49,7 @@ This document describes the future state of ColdVox documentation architecture, docs/ ├── architecture.md # High-level system overview & vision ├── standards.md # Documentation standards & policies -├── agents.md # AI agent guidelines & documentation index +├── (no agents.md) # Agent instructions live at repo root (AGENTS.md) ├── dependencies.md # Project dependencies (Cargo, system) │ ├── domains/ # Domain-specific documentation diff --git a/docs/plans/documentation/proposal-documentation-restructure.md b/docs/plans/documentation/proposal-documentation-restructure.md index 633c12c6..b9129e1d 100644 --- a/docs/plans/documentation/proposal-documentation-restructure.md +++ b/docs/plans/documentation/proposal-documentation-restructure.md @@ -9,6 +9,10 @@ last_reviewed: 2025-10-19 # Proposal: Documentation Restructure and Standards (v3) +> **Note (current-state override)**: This proposal predates the current agent-instruction policy. +> `AGENTS.md` at the repo root is canonical for agents, and **`docs/agents.md` should not be created**. +> Tool-specific entrypoints (e.g. `.github/copilot-instructions.md`, `.kilocode/rules/agents.md`) must reference or mirror `AGENTS.md`. + This document outlines a plan to restructure the project's documentation to improve clarity, maintainability, governance, and enforcement of standards. This version adds GitHub governance workflows (auto-merge, merge modes, branch protection), playbooks organization, explicit documentation exceptions, and an index strategy for agents. ## 1. Guiding Principles @@ -25,7 +29,7 @@ This document outlines a plan to restructure the project's documentation to impr docs/ ├── architecture.md # High-level overview, linking to domain details ├── standards.md # Comprehensive documentation standards guide -├── agents.md # Guidelines for AI agents, including the documentation index +├── (no agents.md) # Agent instructions live at repo root (AGENTS.md) ├── dependencies.md # Project dependency documentation (e.g., Cargo, system) ├── repo/ # Repo-level meta documentation │ ├── gitignore.md # Rationale and structure of .gitignore @@ -112,9 +116,9 @@ This new file will define: - `.github/` workflows, issue/PR templates (policy documents live in `/docs` but YAML config remains in `.github/`) - **`.gitignore` Documentation:** Covered in `/docs/repo/gitignore.md` and referenced from standards. -### b. Documentation Index (in `docs/agents.md` and mirrored in `CLAUDE.md`) +### b. Documentation Index (in `AGENTS.md` and referenced by `CLAUDE.md`) -`docs/agents.md` will contain a well-formatted index to help agents (and humans) locate all documentation. +`AGENTS.md` (repo root) should contain a well-formatted index to help agents (and humans) locate all documentation. ```markdown ### Documentation Index @@ -199,7 +203,7 @@ This section captures the proposed repo governance and the feasibility of enforc - Project-specific nuances (e.g., which checks are required for ColdVox): - `docs/playbooks/project-specific/coldvox_documentation_playbook.md` - Agent awareness and quick-links: - - `docs/agents.md` (index) and `CLAUDE.md` (pointer + index) + - `AGENTS.md` (canonical) and `CLAUDE.md` (pointer/import) ## 7. Automated File Watcher and Logging (Docs Changes) @@ -215,8 +219,8 @@ This section captures the proposed repo governance and the feasibility of enforc ## 9. Index Locations for Agents and Claude -- `docs/agents.md`: canonical, structured documentation index with headings and links. -- `CLAUDE.md`: retained as a thin file that mirrors the index and links to `docs/agents.md` for details. +- `AGENTS.md`: canonical, structured documentation index with headings and links. +- `CLAUDE.md`: retained as a thin file that imports or references `AGENTS.md`. ## 10. CI Playbook: Repository Structure Visualizations (Requirements + Options) diff --git a/mise.toml b/mise.toml index ca02293a..8f98d0b7 100644 --- a/mise.toml +++ b/mise.toml @@ -43,7 +43,7 @@ set -euo pipefail pre-commit install # Enable repo-tracked git hooks and ensure AGENTS mirrors are hardlinked. -./scripts/install_git_hardlink_hooks.sh >/dev/null +./scripts/install_git_hardlink_hooks.sh --quiet """ # --- TASK DELEGATION LAYER --- diff --git a/scripts/ensure_agent_hardlinks.sh b/scripts/ensure_agent_hardlinks.sh index 49bfe1e2..0b685ddb 100755 --- a/scripts/ensure_agent_hardlinks.sh +++ b/scripts/ensure_agent_hardlinks.sh @@ -1,6 +1,11 @@ #!/usr/bin/env bash set -euo pipefail +quiet=0 +if [[ "${1:-}" == "--quiet" ]]; then + quiet=1 +fi + repo_root="$({ cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd })" @@ -17,10 +22,97 @@ fi mkdir -p "$(dirname "$dst1")" "$(dirname "$dst2")" -# Replace destination files with hard links to AGENTS.md. -# This is safe even if Git doesn't preserve hardlinks across clones: rerun anytime. -ln -f "$src" "$dst1" -ln -f "$src" "$dst2" +say() { + if [[ "$quiet" -eq 0 ]]; then + echo "$@" + fi +} + +inode_of() { + local path="$1" + if stat -c '%i' "$path" >/dev/null 2>&1; then + stat -c '%i' "$path" + return 0 + fi + if stat -f '%i' "$path" >/dev/null 2>&1; then + stat -f '%i' "$path" + return 0 + fi + return 1 +} + +link_count_of() { + local path="$1" + if stat -c '%h' "$path" >/dev/null 2>&1; then + stat -c '%h' "$path" + return 0 + fi + if stat -f '%l' "$path" >/dev/null 2>&1; then + stat -f '%l' "$path" + return 0 + fi + return 1 +} + +link_or_copy() { + local dst="$1" + + # Remove symlinks explicitly; ln -f replaces regular files but not all symlinks reliably. + if [[ -L "$dst" ]]; then + rm -f "$dst" + fi + + if ln -f "$src" "$dst" 2>/dev/null; then + return 0 + fi + + # If hardlinking fails (e.g., cross-filesystem), keep content correct but warn. + cp -f "$src" "$dst" + echo "warning: could not hardlink $dst; copied contents instead" >&2 + return 0 +} + +is_hardlinked_pair() { + local a="$1" + local b="$2" -# Show inode + link count for confirmation. -stat -c '%i %h %n' "$src" "$dst1" "$dst2" + local ia ib + if ia="$(inode_of "$a")" && ib="$(inode_of "$b")"; then + [[ "$ia" == "$ib" ]] + return $? + fi + + # Fallback: inode via ls -i (portable enough for typical *nix). + ia="$(ls -di "$a" 2>/dev/null | awk '{print $1}')" || return 1 + ib="$(ls -di "$b" 2>/dev/null | awk '{print $1}')" || return 1 + [[ "$ia" == "$ib" ]] +} + +ensure_pair() { + local dst="$1" + + link_or_copy "$dst" + + if ! cmp -s "$src" "$dst"; then + echo "error: $dst does not match $src" >&2 + exit 1 + fi + + if ! is_hardlinked_pair "$src" "$dst"; then + echo "error: $dst is not hardlinked to $src (same contents, different inode)" >&2 + echo "hint: ensure both files are on the same filesystem; rerun scripts/ensure_agent_hardlinks.sh" >&2 + exit 2 + fi +} + +ensure_pair "$dst1" +ensure_pair "$dst2" + +src_inode="$(inode_of "$src" 2>/dev/null || true)" +src_links="$(link_count_of "$src" 2>/dev/null || true)" + +if [[ -n "$src_inode" && -n "$src_links" ]]; then + say "AGENTS mirrors hardlinked (inode=$src_inode links=$src_links)" +else + say "AGENTS mirrors hardlinked" +fi diff --git a/scripts/install_git_hardlink_hooks.sh b/scripts/install_git_hardlink_hooks.sh index 342d361a..97596c26 100755 --- a/scripts/install_git_hardlink_hooks.sh +++ b/scripts/install_git_hardlink_hooks.sh @@ -1,6 +1,11 @@ #!/usr/bin/env bash set -euo pipefail +quiet=0 +if [[ "${1:-}" == "--quiet" ]]; then + quiet=1 +fi + repo_root="$({ cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd })" @@ -19,7 +24,15 @@ fi chmod +x "$hooks_path/post-checkout" "$hooks_path/post-merge" "$repo_root/scripts/ensure_agent_hardlinks.sh" -git -C "$repo_root" config core.hooksPath .githooks +prev_hooks_path="$(git -C "$repo_root" config --local --get core.hooksPath || true)" +git -C "$repo_root" config --local core.hooksPath .githooks + +if [[ "$quiet" -eq 0 ]]; then + if [[ -n "$prev_hooks_path" && "$prev_hooks_path" != ".githooks" ]]; then + echo "Updated repo hooks via core.hooksPath: $prev_hooks_path -> .githooks" + else + echo "Enabled repo hooks via core.hooksPath=.githooks" + fi +fi -echo "Enabled repo hooks via core.hooksPath=.githooks" -"$repo_root/scripts/ensure_agent_hardlinks.sh" +"$repo_root/scripts/ensure_agent_hardlinks.sh" ${quiet:+--quiet}