diff --git a/.eamos-core/docs/rfc/0001-eamos-meeting-os.md b/.eamos-core/docs/rfc/0001-eamos-meeting-os.md index 6a12805..bfbbaed 100644 --- a/.eamos-core/docs/rfc/0001-eamos-meeting-os.md +++ b/.eamos-core/docs/rfc/0001-eamos-meeting-os.md @@ -235,6 +235,10 @@ draft/approve/own what), and the invariant *humans hold every terminal gate*. - **Persona** — specialized agents under `agent/*.md`: `exec-briefer`, `facilitator`, `risk-analyst`, `rca-lead`, `retro-coach`, `discovery-researcher`, `minute-taker`, plus the meeting architect. + +> **Erratum (2026-07, #65).** As built, the `agent/*.md` persona files have not shipped: the +> meeting-architect persona lives in `AGENTS.md`, and the specialized personas are tracked in the +> ROADMAP backlog. The persona ≠ authority separation and the non-delegable gates hold as designed. - **Authority** — a path→role ownership map over deliverables, and an escalation ladder `facilitator → meeting-owner → human`. The non-delegable gates: `manifest-confirmed`, `human-runs-the-room`. The agent **never sends material to real executives** and **never runs a @@ -262,6 +266,12 @@ archetype × altitude) is data too, mirroring EADOS's `eval/rubric.md`. Initial shaping respected: slide budget, jargon level, lead-with), `completeness` (every archetype- required section present), `review-passed`, `human-runs-the-room`, `series-updated`. +> **Erratum (2026-07, #65).** As built, there is no `orchestrator/os/gate/` directory: the gates +> are code in `tools/eamos_lint.py` (validated by `tools/tests/`), while their **vocabularies** +> are data under `orchestrator/os/` — the manifest schema, the intake taxonomy, the deliverable +> registries, the chrome labels, the themes. "Gates as data" is tracked in the ROADMAP backlog. +> The rubric is data as designed (`eval/rubric.yaml`). + ## 11. Enterprise lens (confidentiality & regulatory) Meeting material is among the most sensitive enterprise data: board financials, comp/layoffs (HR), diff --git a/.eamos-core/tools/check_docs.py b/.eamos-core/tools/check_docs.py new file mode 100644 index 0000000..7f3688f --- /dev/null +++ b/.eamos-core/tools/check_docs.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +"""Doc-path check (#65): every repo path the top-level docs reference must exist in the tree. + +For an agent-first repo the contract is load-bearing documentation — an agent told to load a +persona from a directory that does not exist will fail or, worse, improvise one. This is the doc +equivalent of the gates the repo already believes in: extract every path-looking reference from +AGENTS.md / README.md / CLAUDE.md (markdown link targets, inline-code paths, and AGENTS.md's §4 +layout tree) and fail loudly, listing each broken reference. + + python .eamos-core/tools/check_docs.py + +A prose path may be written relative to the repo root or to `.eamos-core/` (both are natural in +context); a `*` glob must match at least one file. `build/` outputs are transient by design and +skipped. +""" + +import glob as globmod +import os +import re +import sys + +TOOLS = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, TOOLS) +import _cli # noqa: E402 (utf8_stdio, #54) + +ROOT = os.path.dirname(os.path.dirname(TOOLS)) +DOCS = ("AGENTS.md", "README.md", "CLAUDE.md") +BASES = ("", ".eamos-core") +LINK_RE = re.compile(r"\]\(([^)#?\s]+)\)") +CODE_RE = re.compile(r"`([^`\s]+)`") +TREE_RE = re.compile(r"^([│ ]*)(?:├──|└──)\s+(\S+)") + + +def _exists(path): + for base in BASES: + candidate = os.path.join(ROOT, base, path) + if "*" in path: + if globmod.glob(candidate): + return True + elif os.path.exists(candidate): + return True + return False + + +def _link_paths(text): + return [m.group(1) for m in LINK_RE.finditer(text) + if not m.group(1).startswith(("http://", "https://", "mailto:"))] + + +def _code_paths(text): + """Inline-code spans that look like repo paths: contain a '/', no placeholders/options.""" + out = [] + for m in CODE_RE.finditer(text): + tok = m.group(1) + if "/" not in tok or tok.startswith(("http", "--", "#", "build/")): + continue + if any(c in tok for c in "<>{}$()«⟨"): # placeholders / prose, not paths + continue + out.append(tok.rstrip("/").rstrip(".,;:")) + return out + + +def _expand_braces(name): + m = re.match(r"(.*)\{([^}]*)\}(.*)", name) + return [f"{m.group(1)}{x}{m.group(3)}" for x in m.group(2).split(",")] if m else [name] + + +def _tree_paths(text): + """Paths from AGENTS.md's fenced layout tree: depth = marker column / 4.""" + paths, stack, in_tree = [], [], False + for line in text.split("\n"): + if not in_tree and line.strip() == "```text": + in_tree = True + continue + if in_tree and line.strip() == "```": + break + m = TREE_RE.match(line) if in_tree else None + if not m: + continue + depth = len(m.group(1)) // 4 + stack = stack[:depth] + for name in _expand_braces(m.group(2)): + paths.append("/".join(stack + [name.rstrip("/")])) + stack.append(m.group(2).rstrip("/")) + return paths + + +def main(): + _cli.utf8_stdio() # Windows: piped stdout must stay UTF-8 (#54) + broken = [] + for doc in DOCS: + text = open(os.path.join(ROOT, doc), encoding="utf-8").read() + refs = _link_paths(text) + _code_paths(text) + if doc == "AGENTS.md": + refs += _tree_paths(text) + for ref in refs: + if not _exists(ref): + broken.append(f"{doc}: '{ref}' does not exist in the tree") + if broken: + print("check_docs: FAIL — the docs reference paths that do not exist (#65)\n") + for b in broken: + print(f" {b}") + print(f"\n{len(broken)} broken reference(s).") + return 1 + print("check_docs: OK — every doc-referenced path resolves") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 908a9e9..d44c6bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,9 @@ jobs: - name: Compile every tool run: python -m py_compile .eamos-core/tools/*.py + - name: Doc-path check (top-level docs reference only real paths, #65) + run: python .eamos-core/tools/check_docs.py + - name: Unit tests (loader, render, gates, flows) run: python -m unittest discover -s .eamos-core/tools/tests -p "test_*.py" diff --git a/AGENTS.md b/AGENTS.md index ef4e8c9..b9e98cb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,10 +10,11 @@ The master design is [RFC-0001](.eamos-core/docs/rfc/0001-eamos-meeting-os.md); ## 1. Persona You are an **Enterprise Project Architect / agentic-OS engineer** (20+ yrs). Two hats: maintain -the factory (archetypes, deck-IR, templates, gates, lint) and, on request, prepare the material -and the regie for one meeting. Specialized meeting personas live in `.eamos-core/agent/*.md` -(`exec-briefer`, `facilitator`, `risk-analyst`, `rca-lead`, `retro-coach`, `discovery-researcher`, -`minute-taker`). +the factory (archetypes, deck-IR, emitters, gates, lint) and, on request, prepare the material +and the regie for one meeting. Specialized meeting personas (exec-briefer, facilitator, +risk-analyst, rca-lead, retro-coach, discovery-researcher, minute-taker) are **planned, not yet +shipped** — tracked in the [ROADMAP backlog](ROADMAP.md); until they land, this file is the only +persona (see the RFC-0001 §8 erratum). ## 2. Language (three tiers — RFC §7) @@ -42,27 +43,29 @@ Its genericity is factored into data layers (RFC §3): - **Meeting manifest** — `orchestrator/examples/*.yaml` shape: the maintainer's answers + the typed inputs ledger, one source of truth. - **Deck-IR** — the deterministic intermediate representation that gates run on (RFC §5). -- **Templates** — deliverable templates the deck-IR renders into (`.pptx`/`.docx`/`.md`). +- **Emitters** — the cosmetic IR → file hop (`tools/emit_md.py` and friends: Markdown, PPTX, DOCX, + SVG, XLSX), themed by the token files in `orchestrator/os/themes/`. There is no templates + directory: a deliverable's form comes from the IR plus data (registry params + theme tokens). ## 4. Repository Layout ```text . ├── AGENTS.md # this file — governs work ON EAMOS -├── CLAUDE.md / GEMINI.md # tool adapters → defer here +├── CLAUDE.md # tool adapter → defers here ├── README.md # what EAMOS is and how it works ├── ROADMAP.md # the plan (covers RFC-0001) -└── .eamos-core/ # ALL factory machinery — one ignorable folder - ├── agent/ # the meeting architect + specialized personas - ├── orchestrator/ # the engine: interview, archetypes, deck-ir, render - │ ├── archetypes/ # the ~8 archetype profiles (data) - │ ├── os/ # machine-readable specs: workflow, authority, deck-ir, gate - │ ├── commands/ # phase commands: intake, structure, draft, review, facilitate, follow-up +├── setup/ # guided installer (M8): POSIX / macOS / PowerShell / cmd +└── .eamos-core/ # ALL factory machinery — one ignorable folder + ├── orchestrator/ # the engine: archetypes, overlays, intake, machine specs + │ ├── archetypes/ # the archetype profiles (data) + │ ├── functions/ # function packs (axis 3, data) + │ ├── os/ # machine-readable specs: manifest, deck-ir, deliverables, + │ │ # intake, series, localization, themes, confidentiality, … │ └── examples/ # reference meeting manifests (e.g. qbr-c-level.yaml) - ├── templates/ # deliverable templates (the output) - ├── tools/ # eamos_lint.py (self-lint), render.py, emit_*.py - ├── eval/ # per-archetype×altitude rubric - └── docs/{rfc,adr}/ # the design of record + ├── tools/ # eamos_lint.py (self-lint), render.py, emit_*.py, series.py, … + ├── eval/ # per-archetype×altitude rubric (rubric.yaml) + └── docs/{rfc,adr,i18n}/ # the design of record ``` The dot-prefix means a consumer ignores the whole factory with one `.eamos-core/` line. diff --git a/CLAUDE.md b/CLAUDE.md index 0e39456..f76de5b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,7 +6,7 @@ This file is auto-loaded by **Claude Code**. The full agent contract for working ## TL;DR (do not skip — read AGENTS.md anyway) - **You are an Enterprise Project Architect / agentic-OS engineer** (20+ yrs). Two hats: maintain - the factory (archetypes, deck-IR, templates, gates, lint) and, on request, prepare the material + the factory (archetypes, deck-IR, emitters, gates, lint) and, on request, prepare the material and the regie for one meeting. - **EAMOS is the second instance of the EADOS pattern.** Same machine (interview → manifest → profiles → templates → render → gate → roles), different output (meeting material, not repos). diff --git a/ROADMAP.md b/ROADMAP.md index 32b7ce5..2381491 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -145,6 +145,8 @@ projections), **not** RAG-synthesis over arbitrary sources. - [ ] Function packs **archetype-aware** — a pack's `add_sections` should only land in relevant archetypes (today they apply to all; worked around in the references) - [ ] More rubric cells (every archetype × altitude); apply the per-region localization norms - [ ] More reference meetings (a non-QBR flagship); `tools/tests/` coverage as features land +- [ ] Specialized meeting personas (`agent/*.md`, RFC-0001 §8) + phase commands — referenced by the design, not yet shipped (#65) +- [ ] Gates as data (`orchestrator/os/gate/`, RFC-0001 §10) — today the gates are code in `tools/eamos_lint.py` with their vocabularies as data (#65) ---