scripts.gen_brief_pack

Reference › scripts › gen_brief_pack

scripts/gen_brief_pack.py builds a dispatch-time context pack for swarm agent briefs, so a builder does not have to re-grep the repository. A human or the orchestrating session runs it before writing a brief; nothing imports it.

Options: --files takes one or more repository-relative glob patterns (** is supported), --symbols takes symbol names, --source is a comma-separated list of source directories passed to the AST toolkit (default src/orchestrata_ultimate,tests, so test consumers appear), and --out writes to a file instead of standard output. At least one of --files and --symbols is required. build_pack composes a markdown document from pure pieces: resolve_files expands the globs, first_docstring_line and file_to_dotted_module give a file inventory, and run_ast_tool shells out to serialize_codebase_ast for refs_for_symbol and who_imports_for_module. extract_file_paths pulls the files that tool output mentions so related test modules can be listed. It writes only the pack, either to standard output or to the --out path.

At a glance

Source scripts/gen_brief_pack.py
Lines of code 340
Classes 0
Functions 9
Imports (internal) none
Imported by none
Tests that import it none

Class diagram

No classes; see Functions.

Dependency diagram

No internal imports and no importers.

API

Functions

Function Signature Summary
resolve_files resolve_files(patterns: list[str], repo_root: Path = REPO_ROOT) -> list[str] Expand --files glob pattern(s) (** supported) to a sorted, deduped, repo-relative file list.
first_docstring_line first_docstring_line(repo_root: Path, rel_path: str) -> str First non-blank line of rel_path's module docstring, or "" when there is none / it isn't parseable Python.
file_to_dotted_module file_to_dotted_module(rel_path: str) -> str | None src/orchestrata_ultimate/x/y.py -> orchestrata_ultimate.x.y.
run_ast_tool run_ast_tool(args: list[str], repo_root: Path = REPO_ROOT, timeout: float = 120.0) -> str Shell out to serialize_codebase_ast.py and return its stdout, with any subprocess error appended inline rather than raised — a brief pack with one degraded section beats an orchestrator getting…
refs_for_symbol refs_for_symbol(name: str, source: str, repo_root: Path = REPO_ROOT) -> str
who_imports_for_module who_imports_for_module(dotted: str, source: str, repo_root: Path = REPO_ROOT) -> str
extract_file_paths extract_file_paths(text: str) -> set[str] Every path/to/x.py this AST-tool output mentioned on a line of REAL evidence — a DEF/IMP/USE or who-imports hit.
build_pack build_pack(files_patterns: list[str], symbols: list[str], *, source: str = 'src/orchestrata_ultimate,tests', repo_root: Path = REPO_ROOT) -> str Assemble the full markdown brief pack.
main main(argv: list[str] | None = None) -> int

Source

Permalink: https://gitlab.com/MSamy/orchestrata-ultimate-architecture/-/blob/a4cbc2bdf/scripts/gen_brief_pack.py

#!/usr/bin/env python3
"""gen_brief_pack.py — dispatch-time context pack for swarm agent briefs.

A retro of swarm-orchestration cost centers found builders re-grepping the
same "where is this defined / who uses it / what tests cover it" questions
an orchestrator could answer once, at dispatch time, from tooling that
already exists. This CLI composes THREE already-built tools — no new static
analysis of its own:

- ``scripts/serialize_codebase_ast.py refs``        (symbol definitions +
  import sites + use sites)
- ``scripts/serialize_codebase_ast.py who-imports``  (reverse import graph,
  module granularity)
- plain ``glob`` + ``ast.get_docstring`` for the file inventory section

into one markdown "brief pack" an orchestrator pastes (or ``--out``-writes)
into a delegated agent's prompt.

CLI:
    python scripts/gen_brief_pack.py --files "src/orchestrata_ultimate/knowledge_graph/graph_client.py"
    python scripts/gen_brief_pack.py --symbols GraphClient BoltSyncRepository
    python scripts/gen_brief_pack.py --files "src/orchestrata_ultimate/knowledge_graph/*.py" \\
        --symbols GraphClient --out /tmp/pack.md

Output sections:
    1. File inventory       — every file matched by ``--files`` glob(s),
                               with its module docstring's first line.
    2. Symbol references    — ``refs`` output for each ``--symbols`` name.
    3. Module reverse-imports — ``who-imports`` for the dotted module path
                               of every ``--files`` match under ``src/``.
    4. Related test modules — every ``tests/*.py`` file that showed up as a
                               reference/import site in sections 2-3 (no
                               separate name-matching heuristic — this is
                               exactly the same data, filtered).
"""

from __future__ import annotations

import argparse
import ast
import glob as glob_mod
import re
import subprocess
import sys
from pathlib import Path

REPO_ROOT = Path(__file__).resolve().parent.parent
AST_TOOL = REPO_ROOT / "scripts" / "serialize_codebase_ast.py"

#: A ``path/to/file.py:123`` reference inside AST-toolkit output — used to
#: harvest every file path the ``refs``/``who-imports`` calls surfaced, so
#: the "related test modules" section needs no separate name-matching pass.
_FILE_LINE_RE = re.compile(r"(\S+\.py):\d+")

#: Evidence the AST toolkit itself labels as weak. ``refs`` prefixes a bare
#: string-literal occurrence with ``STR`` and tags the line
#: ``[STRING-LITERAL — weak evidence]``; such a line names a file that merely
#: MENTIONS the symbol's name, never one that references the symbol. Matching
#: on the toolkit's own marker (not on a re-derived heuristic) keeps this
#: filter honest if the toolkit's wording changes: the marker is the contract.
#: Both hyphen forms are accepted so an em-dash/hyphen change cannot silently
#: disable the filter.
_WEAK_EVIDENCE_RE = re.compile(r"\bSTRING-LITERAL\b|\bWEAK\b", re.IGNORECASE)


# ---------------------------------------------------------------------------
# File inventory (section 1)
# ---------------------------------------------------------------------------


def resolve_files(patterns: list[str], repo_root: Path = REPO_ROOT) -> list[str]:
    """Expand ``--files`` glob pattern(s) (``**`` supported) to a sorted,
    deduped, repo-relative file list."""
    matched: set[str] = set()
    for pattern in patterns:
        for hit in glob_mod.glob(str(repo_root / pattern), recursive=True):
            p = Path(hit)
            if not p.is_file():
                continue
            try:
                matched.add(str(p.relative_to(repo_root)))
            except ValueError:
                matched.add(hit)
    return sorted(matched)


def first_docstring_line(repo_root: Path, rel_path: str) -> str:
    """First non-blank line of ``rel_path``'s module docstring, or ``""``
    when there is none / it isn't parseable Python."""
    path = repo_root / rel_path
    if path.suffix != ".py":
        return ""
    try:
        tree = ast.parse(path.read_text(encoding="utf-8"))
    except SyntaxError, UnicodeDecodeError, OSError:
        return ""
    doc = ast.get_docstring(tree)
    if not doc:
        return ""
    for line in doc.splitlines():
        stripped = line.strip()
        if stripped:
            return stripped
    return ""


# ---------------------------------------------------------------------------
# AST-toolkit composition (sections 2-3)
# ---------------------------------------------------------------------------


def file_to_dotted_module(rel_path: str) -> str | None:
    """``src/orchestrata_ultimate/x/y.py`` -> ``orchestrata_ultimate.x.y``.

    ``None`` for anything not under a ``src/`` directory (that's the only
    tree ``who-imports`` reasons about as an importable package) or that
    isn't itself a ``.py`` file.
    """
    parts = Path(rel_path).parts
    if "src" not in parts:
        return None
    idx = parts.index("src")
    mod_parts = list(parts[idx + 1 :])
    if not mod_parts:
        return None
    if mod_parts[-1] == "__init__.py":
        mod_parts = mod_parts[:-1]
    elif mod_parts[-1].endswith(".py"):
        mod_parts[-1] = mod_parts[-1][:-3]
    else:
        return None
    return ".".join(mod_parts) if mod_parts else None


def run_ast_tool(
    args: list[str], repo_root: Path = REPO_ROOT, timeout: float = 120.0
) -> str:
    """Shell out to ``serialize_codebase_ast.py`` and return its stdout,
    with any subprocess error appended inline rather than raised — a brief
    pack with one degraded section beats an orchestrator getting nothing
    because one lookup failed.

    Deliberately does NOT force ``--no-daemon``: this tool composes, so it
    must still be correct with no resident ``scripts/ast_daemon.py`` up —
    ``query_ast_daemon`` degrades to the identical local computation on any
    daemon miss (see its docstring) — but when the daemon IS resident (the
    SessionStart hook keeps one warm for this repo) delegating to it turns
    a ~10-15s cold reparse into a sub-2s socket round trip, so there is no
    reason to pay that tax by opting out.
    """
    cmd = [sys.executable, str(AST_TOOL), *args]
    try:
        result = subprocess.run(
            cmd,
            cwd=str(repo_root),
            capture_output=True,
            text=True,
            timeout=timeout,
        )
    except subprocess.TimeoutExpired:
        return f"[gen_brief_pack] AST tool timed out after {timeout}s: {' '.join(args)}"
    out = result.stdout
    if result.returncode != 0:
        out += (
            f"\n[gen_brief_pack] AST tool exited {result.returncode}: "
            f"{result.stderr.strip()[-500:]}\n"
        )
    return out


def refs_for_symbol(name: str, source: str, repo_root: Path = REPO_ROOT) -> str:
    return run_ast_tool(["refs", name, "--source", source], repo_root=repo_root)


def who_imports_for_module(
    dotted: str, source: str, repo_root: Path = REPO_ROOT
) -> str:
    return run_ast_tool(
        ["who-imports", dotted, "--source", source], repo_root=repo_root
    )


def extract_file_paths(text: str) -> set[str]:
    """Every ``path/to/x.py`` this AST-tool output mentioned on a line of
    REAL evidence — a ``DEF``/``IMP``/``USE`` or ``who-imports`` hit.

    Lines the AST toolkit itself marks as weak are skipped. ``refs`` reports a
    bare string-literal occurrence as::

        STR tests/scripts/test_x.py:264 [STRING-LITERAL — weak evidence]

    and harvesting that put a test module under "Related test modules" purely
    because the file mentions the symbol's NAME inside a string. A brief pack
    exists to point an agent at code that actually touches the symbol; a module
    promoted on evidence the producing tool labelled WEAK is false confidence,
    which is the one thing a context pack must not manufacture.
    """
    return {
        m.group(1)
        for line in text.splitlines()
        if not _WEAK_EVIDENCE_RE.search(line)
        for m in _FILE_LINE_RE.finditer(line)
    }


# ---------------------------------------------------------------------------
# Pack assembly
# ---------------------------------------------------------------------------


def build_pack(
    files_patterns: list[str],
    symbols: list[str],
    *,
    source: str = "src/orchestrata_ultimate,tests",
    repo_root: Path = REPO_ROOT,
) -> str:
    """Assemble the full markdown brief pack. Pure composition — see module
    docstring for what each section reuses."""
    lines: list[str] = ["# Context Brief Pack", ""]
    all_text_parts: list[str] = []

    matched_files = resolve_files(files_patterns, repo_root) if files_patterns else []
    lines.append("## File inventory")
    if matched_files:
        for f in matched_files:
            doc = first_docstring_line(repo_root, f)
            lines.append(f"- `{f}`" + (f" — {doc}" if doc else ""))
    else:
        lines.append("_(no `--files` patterns given, or no matches)_")
    lines.append("")

    lines.append("## Symbol references")
    if symbols:
        for name in symbols:
            out = refs_for_symbol(name, source, repo_root)
            all_text_parts.append(out)
            lines.append(f"### `{name}`")
            lines.append("```")
            lines.append(out.strip())
            lines.append("```")
            lines.append("")
    else:
        lines.append("_(no `--symbols` given)_")
        lines.append("")

    lines.append("## Module reverse-imports (who-imports)")
    dotted_seen: set[str] = set()
    any_module = False
    for f in matched_files:
        dotted = file_to_dotted_module(f)
        if dotted is None or dotted in dotted_seen:
            continue
        dotted_seen.add(dotted)
        any_module = True
        out = who_imports_for_module(dotted, source, repo_root)
        all_text_parts.append(out)
        lines.append(f"### `{dotted}`")
        lines.append("```")
        lines.append(out.strip())
        lines.append("```")
        lines.append("")
    if not any_module:
        lines.append("_(no `src/` modules resolved from `--files`)_")
        lines.append("")

    lines.append("## Related test modules")
    test_files = sorted(
        {
            p
            for text in all_text_parts
            for p in extract_file_paths(text)
            if p.startswith("tests/")
        }
    )
    if test_files:
        for t in test_files:
            lines.append(f"- `{t}`")
    else:
        lines.append("_(none found)_")
    lines.append("")

    return "\n".join(lines)


# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(
        description=(
            "Dispatch-time context pack for swarm agent briefs — composes "
            "the AST toolkit's refs/who-imports + a file inventory + related "
            "test modules so builders don't re-grep."
        )
    )
    parser.add_argument(
        "--files",
        nargs="+",
        default=[],
        metavar="GLOB",
        help="Repo-relative glob pattern(s) for the file inventory / "
        "who-imports sections (** supported).",
    )
    parser.add_argument(
        "--symbols",
        nargs="+",
        default=[],
        metavar="NAME",
        help="Symbol name(s) to look up via `refs`.",
    )
    parser.add_argument(
        "--source",
        default="src/orchestrata_ultimate,tests",
        help="Comma-separated source dirs passed through to the AST "
        "toolkit (default: src+tests, so test consumers show up).",
    )
    parser.add_argument(
        "--out", metavar="PATH", help="Write the pack here instead of stdout."
    )
    args = parser.parse_args(argv)

    if not args.files and not args.symbols:
        parser.error("at least one of --files or --symbols is required")

    pack = build_pack(args.files, args.symbols, source=args.source)

    if args.out:
        out_path = Path(args.out)
        out_path.write_text(pack, encoding="utf-8")
        print(f"[gen_brief_pack] wrote {out_path} ({len(pack)} bytes)")
    else:
        print(pack)
    return 0


if __name__ == "__main__":
    sys.exit(main())