This repository has been archived on 2026-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
orchestrator/agent-team/agent_team/nodes/handbook.py

87 lines
3.2 KiB
Python

"""Sea Haven engineering-handbook conventions loader (WS5 handbook seam).
Reads a handbook directory (``SEA_HAVEN_HANDBOOK_DIR`` env or
``~/.sea-haven/engineering-handbook``) and returns a formatted summary of
its ``*.md`` convention files for optional injection into prompt contexts.
Safe no-op contract: if the directory is absent, empty, or any read fails,
:func:`load_handbook_conventions` returns ``""`` and never raises. Callers
treat an empty return as "no handbook available" and omit the context block
rather than failing.
The rsync that delivers the handbook from the Mac to the R720 box, and the
nightly ``.github`` pull (systemd timers), are ATTENDED box steps and are
NOT implemented here.
"""
from __future__ import annotations
import os
from pathlib import Path
from typing import Optional
__all__ = [
"SEA_HAVEN_HANDBOOK_ENV",
"load_handbook_conventions",
]
SEA_HAVEN_HANDBOOK_ENV = "SEA_HAVEN_HANDBOOK_DIR"
_DEFAULT_HANDBOOK_DIR = Path.home() / ".sea-haven" / "engineering-handbook"
# Maximum number of convention files to load (defense-in-depth: avoid
# accidentally summarising a huge handbook dir on first setup).
_MAX_FILES = 20
# Max bytes per file to include in the formatted summary (truncated if larger).
_MAX_FILE_BYTES = 4096
def _handbook_dir(path: Optional[Path | str]) -> Path:
"""Resolve the handbook directory from an explicit path, env, or default."""
if path is not None:
return Path(path)
env = os.environ.get(SEA_HAVEN_HANDBOOK_ENV, "").strip()
if env:
return Path(env)
return _DEFAULT_HANDBOOK_DIR
def load_handbook_conventions(path: Optional[Path | str] = None) -> str:
"""Load engineering-handbook conventions and return a formatted summary.
Reads all ``*.md`` files in the resolved handbook directory (up to
:data:`_MAX_FILES`) and returns a single formatted string suitable for
prepending to a model prompt. Returns ``""`` — never raises — when:
* the directory does not exist or is not a directory;
* no ``*.md`` files are found;
* any read error occurs (the file is skipped silently).
The returned string includes a header and one section per convention
file; callers should include it only when it is non-empty.
"""
try:
hdir = _handbook_dir(path)
if not hdir.is_dir():
return ""
files = sorted(hdir.glob("*.md"))[:_MAX_FILES]
if not files:
return ""
sections: list[str] = []
for fpath in files:
try:
raw = fpath.read_bytes()[:_MAX_FILE_BYTES].decode(
"utf-8", errors="replace"
)
sections.append(f"### {fpath.stem}\n{raw.strip()}")
except Exception: # noqa: BLE001 - safe no-op
continue
if not sections:
return ""
header = (
"## Sea Haven engineering-handbook conventions\n"
"These conventions are from the engineering handbook. Apply them "
"when planning or clarifying. They may not cover every scenario."
)
return header + "\n\n" + "\n\n---\n\n".join(sections)
except Exception: # noqa: BLE001 - safe no-op in all failure modes
return ""