From 19195fb7c9f7de73acbb55a1559a9866f930ef6d Mon Sep 17 00:00:00 2001 From: alex anikin <60673011+anikinsasha@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:58:37 -0700 Subject: [PATCH 1/5] docs(tools): retire dead deprecated-skill rows and the pointers keeping them alive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Deprecated Skills list in Tools.md retires six skill names. Five of them (Images, VideoTranscript, VoiceNarration, YouTube, Sensitive) no longer resolve to anything in the tree, so the rows are archaeology — and the stale pointers still aimed at those skills made them look live: LIFEOS/TOOLS/AddBg.ts:7,13 -> 'Part of the Images skill' + @see skills/Images/SKILL.md LIFEOS/TOOLS/RemoveBg.ts:7 -> 'Part of the Images skill' LIFEOS/TOOLS/GetTranscript.ts -> bun ~/.claude/skills/Videotranscript/Tools/GetTranscript.ts (x4) LIFEOS/TOOLS/YouTubeApi.ts:13 -> bun ~/.claude/skills/YouTube/Tools/YouTubeApi.ts skills/Art/Workflows/{Mermaid,Visualize,Visualize,Essay}.md -> 'use the Images skill' Each pointer now names the tool that actually ships. The four Art lines already carried the correct 'bun ~/.claude/LIFEOS/TOOLS/RemoveBg.ts' command directly underneath; only the label was stale. ExtractTranscript keeps its row: both targets ship (extract-transcript.py and ExtractTranscript.ts), so the name still resolves and the row does real work. The section now states that rule so the next retirement is decidable. Verified: the five retired names have zero remaining occurrences under LifeOS/install/. --- LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md | 7 +------ LifeOS/install/LIFEOS/TOOLS/AddBg.ts | 4 ++-- LifeOS/install/LIFEOS/TOOLS/GetTranscript.ts | 8 ++++---- LifeOS/install/LIFEOS/TOOLS/RemoveBg.ts | 2 +- LifeOS/install/LIFEOS/TOOLS/YouTubeApi.ts | 2 +- LifeOS/install/skills/Art/Workflows/Essay.md | 2 +- LifeOS/install/skills/Art/Workflows/Mermaid.md | 2 +- LifeOS/install/skills/Art/Workflows/Visualize.md | 4 ++-- 8 files changed, 13 insertions(+), 18 deletions(-) diff --git a/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md index 3e33ad626c..7753fdaf2d 100755 --- a/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md +++ b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md @@ -634,14 +634,9 @@ When adding a new utility tool to this system: ## Deprecated Skills -The following skills have been consolidated into this Tools system: +A row belongs here only while the retired name still resolves to something in the tree — otherwise it is archaeology that makes a dead name look live. -- **Images** → `Tools/RemoveBg.ts`, `Tools/AddBg.ts` (2024-12-22) -- **VideoTranscript** → `Tools/GetTranscript.ts` (2024-12-22) -- **VoiceNarration** → Voice server API (2024-12-22) - **ExtractTranscript** → `Tools/extract-transcript.py`, `Tools/ExtractTranscript.ts` (2024-12-22) -- **YouTube** → `Tools/YouTubeApi.ts` (2024-12-22) -- **Sensitive** → `trufflehog` system tool (2024-12-22) Archived skill files have been removed. diff --git a/LifeOS/install/LIFEOS/TOOLS/AddBg.ts b/LifeOS/install/LIFEOS/TOOLS/AddBg.ts index a04dee866f..27eda2ce65 100755 --- a/LifeOS/install/LIFEOS/TOOLS/AddBg.ts +++ b/LifeOS/install/LIFEOS/TOOLS/AddBg.ts @@ -4,13 +4,13 @@ * add-bg - Add Background Color CLI * * Add a solid background color to transparent PNG images. - * Part of the Images skill for LifeOS system. + * Companion to RemoveBg.ts; driven by the Art skill's background workflows. * * Usage: * add-bg input.png "#EAE9DF" output.png * add-bg input.png --ul-brand output.png * - * @see ~/.claude/skills/Images/SKILL.md + * @see ~/.claude/LIFEOS/DOCUMENTATION/Tools/Tools.md */ import { existsSync } from "node:fs"; diff --git a/LifeOS/install/LIFEOS/TOOLS/GetTranscript.ts b/LifeOS/install/LIFEOS/TOOLS/GetTranscript.ts index fdad6bcb53..bdd6d9b382 100755 --- a/LifeOS/install/LIFEOS/TOOLS/GetTranscript.ts +++ b/LifeOS/install/LIFEOS/TOOLS/GetTranscript.ts @@ -4,12 +4,12 @@ * GetTranscript.ts - Extract transcript from YouTube video * * Usage: - * bun ~/.claude/skills/Videotranscript/Tools/GetTranscript.ts - * bun ~/.claude/skills/Videotranscript/Tools/GetTranscript.ts --save + * bun ~/.claude/LIFEOS/TOOLS/GetTranscript.ts + * bun ~/.claude/LIFEOS/TOOLS/GetTranscript.ts --save * * Examples: - * bun ~/.claude/skills/Videotranscript/Tools/GetTranscript.ts "https://www.youtube.com/watch?v=abc123" - * bun ~/.claude/skills/Videotranscript/Tools/GetTranscript.ts "https://youtu.be/abc123" --save transcript.txt + * bun ~/.claude/LIFEOS/TOOLS/GetTranscript.ts "https://www.youtube.com/watch?v=abc123" + * bun ~/.claude/LIFEOS/TOOLS/GetTranscript.ts "https://youtu.be/abc123" --save transcript.txt * * @author LifeOS System * @version 1.0.0 diff --git a/LifeOS/install/LIFEOS/TOOLS/RemoveBg.ts b/LifeOS/install/LIFEOS/TOOLS/RemoveBg.ts index a3c0eb6ee8..48cf81442e 100755 --- a/LifeOS/install/LIFEOS/TOOLS/RemoveBg.ts +++ b/LifeOS/install/LIFEOS/TOOLS/RemoveBg.ts @@ -4,7 +4,7 @@ * remove-bg - Background Removal CLI * * Remove backgrounds from images using local rembg. - * Part of the Images skill for LifeOS system. + * Companion to AddBg.ts; driven by the Art skill's background workflows. * * Usage: * remove-bg input.png # Overwrites original diff --git a/LifeOS/install/LIFEOS/TOOLS/YouTubeApi.ts b/LifeOS/install/LIFEOS/TOOLS/YouTubeApi.ts index a8a9550f0f..384862c4f1 100755 --- a/LifeOS/install/LIFEOS/TOOLS/YouTubeApi.ts +++ b/LifeOS/install/LIFEOS/TOOLS/YouTubeApi.ts @@ -10,7 +10,7 @@ for (const __k of ["LIFEOS_DIR", "LIFEOS_CONFIG_DIR", "PROJECTS_DIR"]) { * YouTubeApi.ts - YouTube Data API v3 client * * Usage: - * bun ~/.claude/skills/YouTube/Tools/YouTubeApi.ts [options] + * bun ~/.claude/LIFEOS/TOOLS/YouTubeApi.ts [options] * * Commands: * channel Get channel statistics diff --git a/LifeOS/install/skills/Art/Workflows/Essay.md b/LifeOS/install/skills/Art/Workflows/Essay.md index 49d04e5979..a7453bcd48 100644 --- a/LifeOS/install/skills/Art/Workflows/Essay.md +++ b/LifeOS/install/skills/Art/Workflows/Essay.md @@ -719,7 +719,7 @@ thumbnail: https://example.com/images/my-header.png For non-blog images that only need transparency, or to remove backgrounds after generation: ```bash -# Use the Images Skill for background removal +# Standalone background removal bun ~/.claude/LIFEOS/TOOLS/RemoveBg.ts /path/to/output.png # Or batch process multiple images diff --git a/LifeOS/install/skills/Art/Workflows/Mermaid.md b/LifeOS/install/skills/Art/Workflows/Mermaid.md index a2bda0c74a..83ee1fe87c 100644 --- a/LifeOS/install/skills/Art/Workflows/Mermaid.md +++ b/LifeOS/install/skills/Art/Workflows/Mermaid.md @@ -667,7 +667,7 @@ ONE-OFF / QUICK PREVIEW: Keep white background (#FFFFFF) GOING INTO BLOG/WEBSITE: Remove background for transparency ``` -**For blog/website use** — use the **Images skill** for background removal: +**For blog/website use** — use `RemoveBg.ts` for background removal: ```bash bun ~/.claude/LIFEOS/TOOLS/RemoveBg.ts /path/to/mermaid-diagram.png diff --git a/LifeOS/install/skills/Art/Workflows/Visualize.md b/LifeOS/install/skills/Art/Workflows/Visualize.md index e0a1de445b..7605a31d53 100644 --- a/LifeOS/install/skills/Art/Workflows/Visualize.md +++ b/LifeOS/install/skills/Art/Workflows/Visualize.md @@ -90,12 +90,12 @@ STYLE: Excalidraw whiteboard sketch with rich graphics ``` DEFAULT: Light Cream/Sepia #F5E6D3 (matches blog aesthetic) WHITE ONLY IF: User explicitly requests "white background" in prompt -TRANSPARENT: Use Images skill to remove background for overlay use +TRANSPARENT: Use RemoveBg.ts to remove background for overlay use ``` **Light Cream (#F5E6D3) is the DEFAULT background.** Only use white (#FFFFFF) if the user explicitly requests it. -**For transparent background** — use the **Images skill** for background removal: +**For transparent background** — use `RemoveBg.ts` for background removal: ```bash bun ~/.claude/LIFEOS/TOOLS/RemoveBg.ts /path/to/visualization.png From dae195a1e8e8b86d7869b797f785c7acfbdc214b Mon Sep 17 00:00:00 2001 From: alex anikin <60673011+anikinsasha@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:59:25 -0700 Subject: [PATCH 2/5] docs: give executed-model verification a single home MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Inference-max Fable-carrier mechanism (subprocess spawn, modelUsage read-back, verifyExecutedModel, the downgrade log) was written out three times: RouterSystem.md § 3 Select the model, Tools.md § Inference.ts, and the Architecture Router row. Three copies drift independently, and two of them already disagreed on how the check works. RouterSystem.md keeps the mechanism — it sits inside the select-model stage, which is where the behavior belongs. The other two become pointers. Worth naming: RouterSystem.md opens with a RETIRED banner, but that banner retires the classify and route-effort stages. Select-model survived, so the paragraph the pointers aim at is live text inside a doc labeled history. The Tools.md pointer says so, otherwise the banner reads as 'ignore this'. --- LifeOS/install/LIFEOS/DOCUMENTATION/LifeosSystemArchitecture.md | 2 +- LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LifeOS/install/LIFEOS/DOCUMENTATION/LifeosSystemArchitecture.md b/LifeOS/install/LIFEOS/DOCUMENTATION/LifeosSystemArchitecture.md index 18f206a907..b55abd66ed 100755 --- a/LifeOS/install/LIFEOS/DOCUMENTATION/LifeosSystemArchitecture.md +++ b/LifeOS/install/LIFEOS/DOCUMENTATION/LifeosSystemArchitecture.md @@ -587,7 +587,7 @@ System file inventory by pipeline. When you modify a file, trace its pipeline to | **Security** | `LIFEOS/LIFEOS_SYSTEM_PROMPT.md` § Security Protocol (constitutional rule), `settings.json` `permissions.deny` (native harness denylist), `hooks/Safety.hook.ts` (consolidated PermissionRequest + PostToolUse on WebFetch \| WebSearch), `hooks/lib/safety-classifier.ts` (shape catalog + shell-aware classifier with single-quote pre-pass) | | **Algorithm** | `Algorithm/LATEST` → `Algorithm/v{VERSION}.md` (currently v8.4.0 — the claims restructure: Loop preamble + 15 teeth-annotated done-claims + AlgorithmNudge event layer (unified 2026-07-11: run-scoped + always-on skill-routing/late-ISA/spend; depth-directive row added v8.4.0, 2026-07-12); capabilities.md removed at v7, the system-prompt skill list is the sole capability inventory), `Algorithm/mode-detection.md`, `hooks/ISASync.hook.ts` → `MEMORY/WORK/{slug}/ISA.md`, `skills/ISA/` (canonical Scaffold/Append/Reconcile workflows); **work registry event-sourced (2026-06-10):** all `work.json` writes go through `isa-utils.writeRegistry` → field-level diff events appended to `MEMORY/STATE/work-events.jsonl` (`hooks/lib/work-events.ts`) → locked fold to the derived `work.json` snapshot (offset-stamped, 1MB compaction); `readRegistry` serves snapshot+suffix live views; Pulse SSE triggers off `fs.watch` on STATE with the 100ms poll as fallback; model choice is per-dispatch judgment (2026-07-11 baseline); `EFFORT_MODEL` in `LIFEOS/TOOLS/models.ts` remains the `Inference.ts --level` dial | | **Memory** | `hooks/WorkCompletionLearning.hook.ts`, `hooks/SatisfactionCapture.hook.ts` (RelationshipMemory hook deleted 7.0.0 — dead code), `Tools/KnowledgeHarvester.ts` → `MEMORY/KNOWLEDGE/`, `MEMORY/LEARNING/`; `Tools/SessionHarvester.ts --mine` → `KNOWLEDGE/_harvest-queue/`; `Tools/MemoryRetriever.ts` (BM25 retrieval over typed-item corpus including `_MEMORY.md` hot-layer files), `Tools/KnowledgeGraph.ts` (graph navigation) — read-only. **Autonomic loop (2026-05):** `hooks/MemoryTurnStart.hook.ts` (UserPromptSubmit) + `hooks/MemoryReviewFire.hook.ts` (Stop; cadence merged 2026-07-11) drive `Tools/MemoryReviewer.ts` on cadence (turn≥8 ∧ minutes≥30 ∧ idle≥2). Reviewer emits typed items routed by `Tools/MemorySystem.ts` (single `add(item)` API) over the `Tools/MemoryTypes.ts` registry; `Tools/MutationTier.ts` gates by tier A/B/C/D. Tier-C proposals enqueue to `MEMORY/OBSERVABILITY/pending-proposals.jsonl`; `PULSE/lib/telegram-proposals.ts` + `PULSE/modules/telegram.ts` surface them as `yes/no/edit #id` Telegram replies. `Tools/MemoryStatus.ts` is the read-only `kai status` CLI. **kb-v3 knowledge schema (2026-07-05):** `Tools/KnowledgeSchema.ts` is the pure-data SoT for the KNOWLEDGE archive object-schema (`person\|company\|idea\|blog\|research` — distinct from the write-registry above) + body-safe parse/normalize/validate; `Tools/KnowledgeLint.ts` validates conformance (envelope % vs per-type completeness); `Tools/MigrateKnowledge.ts` migrated ~4,400 notes onto it (body-byte-preserving, idempotent, dry-run default); `Tools/KnowledgeQuery.ts` (`kb query`) filters/sorts on the now-consistent typed fields; `Tools/GenerateKnowledgeSchemaDoc.ts` regenerates `MEMORY/KNOWLEDGE/_schema.md` from the schema; `MemorySystem.renderInitialNote` emits the kb-v3 envelope so new autonomic notes are born conformant. | -| **Router** (RETIRED 2026-07-11) | Classify → route-effort stages retired 2026-07-11 with the mode/tier abolition (`TheRouter.hook.ts` deleted; MINIMAL/NATIVE/ALGORITHM + E1–E5 gone, no successor classifier). **Surviving model routing:** `LIFEOS/TOOLS/models.ts` `EFFORT_MODEL` maps level→model (max→fable / high→opus / medium→sonnet / low→haiku; `LEVEL_TO_HARNESS_EFFORT`; cross-vendor pins; egress-class ceilings) → **dispatch** via `model` param on `Agent()` / `Workflow agent()`, injected by `hooks/AgentInvocation.hook.ts` on unspecified dispatches. `LIFEOS/TOOLS/Inference.ts` applies model selection to utility inference, and is the genuine `max`/Fable carrier (subprocess spawns `claude --model claude-fable-5`; Agent `model:fable` dispatch downgrades to Opus). It verifies the executed model against the JSON envelope's `modelUsage` and logs downgrades to `MEMORY/OBSERVABILITY/model-verification.jsonl` (v6.29.0 — reports what RAN, not what was requested). Full doc (history only): `LIFEOS/DOCUMENTATION/Router/RouterSystem.md` | +| **Router** (RETIRED 2026-07-11) | Classify → route-effort stages retired 2026-07-11 with the mode/tier abolition (`TheRouter.hook.ts` deleted; MINIMAL/NATIVE/ALGORITHM + E1–E5 gone, no successor classifier). **Surviving model routing:** `LIFEOS/TOOLS/models.ts` `EFFORT_MODEL` maps level→model (max→fable / high→opus / medium→sonnet / low→haiku; `LEVEL_TO_HARNESS_EFFORT`; cross-vendor pins; egress-class ceilings) → **dispatch** via `model` param on `Agent()` / `Workflow agent()`, injected by `hooks/AgentInvocation.hook.ts` on unspecified dispatches. `LIFEOS/TOOLS/Inference.ts` applies model selection to utility inference and is the genuine `max`/Fable carrier with executed-model verification — mechanism: `LIFEOS/DOCUMENTATION/Router/RouterSystem.md` § Carrier + verification (also the full Router doc, history only). | | **Hooks** | `hooks/*.hook.ts`, `hooks/handlers/*.ts`, `hooks/lib/*.ts`, `settings.json` | | **Observability** | `hooks/EventLogger.hook.ts` (consolidated 2026-07-11 — absorbed ToolActivityTracker, ToolFailureTracker, SkillExecutionLog, ConfigAudit, StopFailureHandler; appends directly via `fs.appendFileSync`) → `MEMORY/OBSERVABILITY/*.jsonl` | | **Pulse** | `Pulse/pulse.ts` (port 31337), `Pulse/modules/{observability,hooks,wiki,imessage,telegram,user-index,da,work,bunker}.ts`, `Pulse/PULSE.toml`, `Pulse/Observability/src/`, `Pulse/Assistant/module.ts` | diff --git a/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md index 7753fdaf2d..6649449e17 100755 --- a/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md +++ b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md @@ -22,7 +22,7 @@ This file documents single-purpose CLI utilities that have been consolidated fro Single inference tool with four run levels for different speed/capability trade-offs — the same four-level abstraction as `EFFORT_MODEL` in `models.ts` (max→fable, high→opus, medium→sonnet, low→haiku; one-line mapping edit on a lineup change). -**Executed-model verification (v6.29.0).** `--level max` genuinely runs Fable (spawns `claude --model claude-fable-5`), unlike an `Agent(model:fable)` dispatch which downgrades to Opus — so this is the real Fable carrier for E4/E5 reasoning. Every run reads the executed model back from the JSON envelope's `modelUsage` (`verifyExecutedModel` — filters Claude Code's per-turn background haiku pass, then takes the highest-output model as the answer's author and checks its family; presence alone can't tell a tiny classifier pass from real authorship). The result carries `executedModel` + `modelDowngraded`; the CLI prints a `[model] requested=… → executed=…` line to stderr (stdout stays the clean answer); any downgrade is logged to `MEMORY/OBSERVABILITY/model-verification.jsonl`. The tool reports what RAN, never what it requested. +`--level max` is the genuine Fable carrier, and every run verifies the model that actually executed — mechanism and rationale: `LIFEOS/DOCUMENTATION/Router/RouterSystem.md` § Carrier + verification (that doc's banner retires the classify/route-effort stages; select-model, which this section applies, is the stage that survived). **Usage:** ```bash From 1d1388a7b87cb825df9fc681f676f75939fb1d95 Mon Sep 17 00:00:00 2001 From: alex anikin <60673011+anikinsasha@users.noreply.github.com> Date: Thu, 30 Jul 2026 00:02:03 -0700 Subject: [PATCH 3/5] docs(tools): replace Adding New Tools with a placement doctrine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old section said: put a .ts or .py file directly in LIFEOS/TOOLS, 'keep the directory flat - NO subdirectories', document it here. Five directory tools ship under LIFEOS/TOOLS/ today (Conveyor, ISARender, TokenXray, healthsync, llcli), so the rule contradicts the tree it governs, and it gives no guidance at all on shape: what a section should contain, how long it may run, or what does not belong in this file in the first place. The doctrine replacing it covers four things the old section did not: - Three tiers with different registration rules. Flat tools are selective here and exhaustive in the generated registry. Directory tools are exhaustive over the ADOPTED set — a directory existing on disk is not adoption, so an instance is never silently out of compliance for carrying a subsystem it has not committed to. External tools are exhaustive here because nothing else indexes them. - What is not a tool, and where it goes instead: hooks, HTTP routes, harness primitives, changelogs, local-deviation inventories, skills. These are the categories that actually accreted into tool indexes. - One entry template for all tiers, with a per-tier row list. - A ~15-non-blank-line working ceiling. The line count is the smell test; the structural bans (no archaeology, one entry per tool edited in place, at most one table) are the operative rule — a compliant entry cannot get long, and a long entry is already breaking one of them. Also folds in the flat-tool header contract, since the generated registry reads those headers, and keeps stock's 'don't create a separate skill for a CLI command' closer. Every pointer in the two tables resolves against this tree. Not in scope: enforcement. This is doctrine a human follows; --audit reports against it, nothing blocks on it. --- .../LIFEOS/DOCUMENTATION/Tools/Tools.md | 103 +++++++++++++----- 1 file changed, 76 insertions(+), 27 deletions(-) diff --git a/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md index 6649449e17..7b36349657 100755 --- a/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md +++ b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md @@ -1,16 +1,87 @@ --- -version: 1.8.0 +version: 1.9.0 --- -# LifeOS Tools - CLI Utilities Reference +# LifeOS Tools — the tool index > CLI-first is how the Life OS stays deterministic (`LIFEOS/DOCUMENTATION/LifeOs/LifeOsThesis.md`): the hill-climb's moves are code you can script, test, and trust — prompts orchestrate, code executes. -This file documents single-purpose CLI utilities that have been consolidated from individual skills. These are pure command-line tools that wrap APIs or external commands. +This is the index of LifeOS **tools** — the counterpart to `skills/`. A tool is a thing an agent or the principal *invokes*. Skills carry judgment; tools carry determinism. -**Philosophy:** Simple utilities don't need separate skills. Document them here, execute them directly. +## Placement doctrine -**Model:** Following the `Tools/fabric/` pattern - 242+ Fabric patterns documented as utilities rather than individual skills. +The one rule set for what lands in this file and in what shape. Generated flat-tool registry: `FlatTools.md`. + +### What belongs + +A **callable tool** — something you can run: + +| Tier | What it is | Registration | +|---|---|---| +| **Flat tool** | a single file (`*.ts`, `*.sh`, `*.py`) in the `LIFEOS/TOOLS` root | exhaustive in generated `FlatTools.md`; **selective** here | +| **Directory tool** | a subsystem under `LIFEOS/TOOLS//` with its own `package.json` / `src/` / `test/` | **exhaustive over the adopted set** — one pointer section per adopted tool | +| **External tool** | a binary or app LifeOS doctrine depends on but does not ship (`trufflehog`, `rtk`) | **exhaustive** here — nothing else indexes it | + +**The adopted set.** A directory tool registers here when the instance has adopted it — decided that this instance runs it — never merely because the directory exists on disk. An unadopted directory under `LIFEOS/TOOLS/` gets no section until that call is made. + +**The selective flat policy.** A flat tool earns a chapter here only when invocation needs more than one line: non-obvious flags, a small fixed dimension worth a table, or a routing imperative ("use this, never the raw SDK"). Everything else is a row in `FlatTools.md`, generated from the tool's own header and never hand-edited. Absence from this file is not absence from the system — check `FlatTools.md` first. + +### What does not belong + +| Not a tool | Its home | +|---|---| +| Hooks | `../Hooks/HookSystem.md` § Quick Reference Card | +| HTTP routes and Pulse modules | the owning subsystem's doc (`../Pulse/PulseSystem.md`, `../Notifications/NotificationSystem.md`) | +| Claude Code harness primitives (`Monitor`, `Agent`, `Workflow`) | `../Delegation/DelegationSystem.md` § Async Primitives | +| Changelogs, version history, design-decision archaeology | the tool's own `ISA.md` § Decisions / § Changelog | +| "Re-add after every update" inventories for a local deviation | `USER/CUSTOMIZATIONS/` | +| Skills | `skills/` + `../Skills/SkillSystem.md` | + +### The entry template + +Same skeleton at every tier; the tier decides which rows are present. + +```text +H2 (H3 when nested inside a chapter) +**Location:** + +**Usage:** + +**When to use:** +**Depth:** +**Deps:** +``` + +- **Flat tool** — identity · Location · what-it-is · Usage · optional table · When-to-use · Deps. Depth row only if the tool has its own doc. +- **Directory tool** — identity · Location · what-it-is · the stable entrypoint · **Depth** (mandatory: README or ISA). No file inventory, no module list, no migration history — the tool's own docs own all of it. +- **External tool** — identity · Location or install line · what-it-is · Usage · When-to-use. No Depth row; there is nothing local to point at. + +### Anti-bloat rules + +- **A pointer, not a mini-PRD.** Location, one-line identity, how to run it, one depth pointer. Working ceiling, every tier: ~15 non-blank lines per entry (a pointer-only section lands well under it). Longer means the depth belongs in the tool's own docs — the structural bans below, not the line count, are the operative rule. +- **No archaeology.** No design-corpus citations, no migration lists, no decision codes, no test counts, no per-module file inventories, no "born from" origin stories, no dated remediation paragraphs. An entry describes the tool as it is *now*. +- **One entry per tool, edited in place.** A rewrite replaces the entry; it never appends a "current state" block under a stale one. +- **Tables earn their place.** At most one per entry, and only for a small fixed dimension. + +### The flat-tool header + +`FlatTools.md` is rendered from each tool's leading comment block, so that header is the registry's source of truth. Three elements, machine-checked by `bun ~/.claude/LIFEOS/TOOLS/ToolsRegistry.ts --audit`: + +- **Identity line** — ``, separated by an em dash or ` - `. The text after the separator becomes the registry's Purpose cell. +- **Purpose prose** — at least one line beyond the identity line saying what the tool does. +- **Usage block, or a library marker** — a `Usage:` block for anything callable; `not a CLI` or `Consumed by:` for a module that is imported rather than run. + +Optional and judgment-scoped, so it is not machine-enforced: `@see ` naming the tool's governing doc, which becomes the registry's Docs cell. + +### Adding a tool + +1. **Class it** — flat · directory · external. Directory tools are normal, not an exception; the older "keep the directory flat — NO subdirectories" rule governed single-file utilities only and never applied to subsystems. +2. **Flat** — Title-Case filename in the `LIFEOS/TOOLS` root (`GetTranscript.ts`, not `get-transcript.ts`), header block per above, then `bun ~/.claude/LIFEOS/TOOLS/ToolsRegistry.ts` to regenerate `FlatTools.md`. Add a chapter here only under the selective policy. +3. **Directory** — its own doc set (a README, plus an ISA where the tool has a design contract), then one pointer section here. +4. **External** — an entry here with its install line. +5. **Close the build** — run the tool from its final path, and leave `ToolsRegistry.ts --check` clean. + +**Don't create a separate skill** if the entire functionality is just a CLI command with parameters. --- @@ -610,28 +681,6 @@ Monitor({ --- -## Adding New Tools - -When adding a new utility tool to this system: - -1. **Add tool file:** Place `.ts` or `.py` file directly in `~/.claude/LIFEOS/TOOLS/` - - Use **Title Case** for filenames (e.g., `GetTranscript.ts`, not `get-transcript.ts`) - - Keep the directory flat - NO subdirectories - -2. **Document here:** Add section to this file with: - - Tool location (e.g., `~/.claude/`) - - Usage examples - - When to use triggers - - Environment variables (if any) - -3. **Update `CLAUDE.md` routing table:** Ensure TOOLS.md is referenced in the documentation index - -4. **Test:** Verify tool works from new location - -**Don't create a separate skill** if the entire functionality is just a CLI command with parameters. - ---- - ## Deprecated Skills A row belongs here only while the retired name still resolves to something in the tree — otherwise it is archaeology that makes a dead name look live. From b4c8366a73bc65ec2b4e35970abf17748ebf795f Mon Sep 17 00:00:00 2001 From: alex anikin <60673011+anikinsasha@users.noreply.github.com> Date: Thu, 30 Jul 2026 00:03:10 -0700 Subject: [PATCH 4/5] feat(tools): generated flat-tool registry (FlatTools.md) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tools.md documents 21 tools. 134 files sit in the LIFEOS/TOOLS root. The gap is not a documentation backlog — a curated index SHOULD be selective — but without a second surface there is nowhere to look up the other 113, and 'not in Tools.md' silently reads as 'does not exist'. This splits the two jobs. Tools.md stays curated: the tools whose invocation needs more than one line. FlatTools.md is generated from each tool's own leading header and is exhaustive over the root, so absence from the curated index stops meaning absence from the system. hooks/lib/flat-tool-header.ts header parser + contract check + renderer LIFEOS/TOOLS/ToolsRegistry.ts CLI: write / --check / --stdout / --audit DOCUMENTATION/Tools/FlatTools.md generated output, committed Deterministic: no timestamps, LC-stable sort, so regeneration on an unchanged tree is a zero diff and --check works as a staleness gate. Current output over this tree: 134 tools, 32 headers short of the element contract. Those 32 are pre-existing and unchanged by this PR — the registry just makes them addressable (ToolsRegistry.ts --audit lists them by name). Notes on the parser, since headers in this tree vary: - The env-normalization preamble from #1404 is skipped, not read as a header. - An ASCII hyphen only separates an identity line when followed by a space, so a usage line like 'algorithm -m loop -p ' is not mistaken for one. - .sh and .py headers parse too (# comments, Python docstrings), so the registry covers the whole root rather than the .ts subset. - Class comes from what the header declares: an Install* prefix, a com.lifeos.*.plist schedule, or a 'not a CLI' / 'Consumed by:' marker. No hand-maintained lists — a tool reclassifies itself by editing its header. Paths resolve via getLifeosDir(), so plugin installs work. --- .../LIFEOS/DOCUMENTATION/Tools/FlatTools.md | 143 ++++++++++++ .../LIFEOS/DOCUMENTATION/Tools/Tools.md | 1 + LifeOS/install/LIFEOS/TOOLS/ToolsRegistry.ts | 68 ++++++ LifeOS/install/hooks/lib/flat-tool-header.ts | 207 ++++++++++++++++++ 4 files changed, 419 insertions(+) create mode 100644 LifeOS/install/LIFEOS/DOCUMENTATION/Tools/FlatTools.md create mode 100644 LifeOS/install/LIFEOS/TOOLS/ToolsRegistry.ts create mode 100644 LifeOS/install/hooks/lib/flat-tool-header.ts diff --git a/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/FlatTools.md b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/FlatTools.md new file mode 100644 index 0000000000..161fd163af --- /dev/null +++ b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/FlatTools.md @@ -0,0 +1,143 @@ +# Flat Tools — generated registry + +> Generated by `LIFEOS/TOOLS/ToolsRegistry.ts` from the tools' own headers — do not hand-edit. +> Regenerate: `bun ~/.claude/LIFEOS/TOOLS/ToolsRegistry.ts`. Contract: `Tools.md` § Placement doctrine. + +134 tools in the LIFEOS/TOOLS root. 32 headers short of the element contract — `ToolsRegistry.ts --audit` lists them. + +| Tool | Class | Purpose | Docs | +|---|---|---|---| +| ActivityParser.ts | cli | Parse session activity for LifeOS repo update documentation | header | +| AddBg.ts | cli | — | ~/.claude/LIFEOS/DOCUMENTATION/Tools/Tools.md | +| AgentWatchdog.ts | cli | Monitor script for detecting hung background agents | header | +| AlgoPhase.ts | cli | atomic Algorithm phase emitter | header | +| algorithm.ts | cli | — | header | +| AlgorithmPhaseReport.ts | cli | Writes algorithm state to algorithm-phase.json | header | +| ApproveCurrentStateEntries.ts | cli | review and commit proposed CURRENT_STATE entries. | header | +| ArchDecisionHarvest.ts | cli | Harvest architecture decisions from ISA files into LifeosSystemArchitecture.md | header | +| ArchitectureSummaryGenerator.ts | cli | Generate LIFEOS_ARCHITECTURE_SUMMARY.md from source docs | header | +| Banner.ts | cli | — | header | +| BannerMatrix.ts | cli | Matrix Digital Rain LifeOS Banner | header | +| BannerNeofetch.ts | cli | Modern Neofetch-Style LifeOS Banner | header | +| BannerPrototypes.ts | cli | — | header | +| BannerRetro.ts | cli | Retro BBS/DOS Terminal Banner for LifeOS | header | +| BannerTokyo.ts | cli | — | header | +| BillingPathAssertion.ts | cli | verify which credential path a `claude -p` run actually used. | header | +| BlogDiscovery.ts | cli | harvest, topic-score, and queue small/indie blogs for the Feed | header | +| BookmarkSweep.ts | daemon | Periodic sweep that turns X bookmarks into UL ideas. | header | +| BudgetCheck.ts | cli | backpressure against always-on context re-accretion. | header | +| CarrierProbe.ts | cli | end-to-end probe of the Agent-dispatch carrier reality. | header | +| CheckFileBoundary.ts | cli | on-demand SystemFileGuard check. | header | +| Checkpoint.ts | cli | inspection and PREVIEW-ONLY rollback CLI for ISC checkpoints | header | +| CodexUpdate.ts | cli | Keep the OpenAI Codex CLI current. | header | +| CommitmentDetect.ts | cli | Haiku-backed detector for outbound commitments. | header | +| CommitmentLog.ts | cli | Manual capture CLI. Creates a GitHub Issue tagged Type:commitment. | header | +| CommitmentSweep.ts | daemon | Daily sweep over Type:commitment issues. | header | +| ComputeGap.ts | cli | computed view of Current→Ideal delta per dimension. | header | +| ContextAudit.ts | cli | read-only quality audit for constitutional context files. | header | +| CostTracker.ts | cli | Anthropic cost observability for LifeOS | header | +| CrossVendorAudit.ts | cli | Forge audit-mode tool (cross-vendor audit; formerly Cato) | header | +| current-work-dir.ts | cli | — | header | +| DAGrowth.ts | cli | — | header | +| DAInterview.ts | cli | — | header | +| DASchedule.ts | cli | CLI for managing DA scheduled tasks | header | +| DeriveDenyHashes.ts | cli | turn the principal's PRIVATE corpus into a SALTED-HASH | header | +| DerivedSync.ts | cli | Detect manual USER source edits and regenerate derived LifeOS artifacts. | header | +| DocCheck.ts | cli | Documentation integrity verifier | header | +| Doctor.ts | cli | LifeOS capability prober and manifest writer. | header | +| DoctrineReplay.ts | cli | sampled doctrine-coverage replay over archived ISAs. | header | +| extract-transcript.py | cli | — | header | +| ExtractTranscript.ts | cli | — | header | +| FailureCapture.ts | cli | Full Context Failure Analysis System | header | +| FeatureRegistry.ts | cli | — | header | +| ForgeProgress.ts | cli | — | header | +| FreshnessCache.ts | cli | render-path cache for the statusline FRESH section. | header | +| GenerateKnowledgeSchemaDoc.ts | cli | regenerate `MEMORY/KNOWLEDGE/_schema.md` FROM | header | +| GenerateTelosSummary.ts | cli | Reads TELOS source files and generates a compressed | header | +| GetCounts.ts | cli | Single Source of Truth for LifeOS System Counts | header | +| GetTranscript.ts | cli | Extract transcript from YouTube video | header | +| gmail.ts | cli | — | header | +| Grok.ts | cli | xAI Grok search client (Agent Tools API) | header | +| GrokAudit.ts | cli | Grok cross-vendor audit voice (xAI lineage) | header | +| HarvestExecutor.ts | cli | — | header | +| HealthSnapshot.ts | cli | — | header | +| HealthSync.ts | cli | — | header | +| Inference.ts | cli | Unified inference tool with four run levels | header | +| InstallBlogDiscovery.ts | installer | Materialize com.lifeos.blogdiscovery.plist.template and bootstrap it. | header | +| InstallBookmarkSweep.ts | installer | Materialize com.lifeos.bookmarksweep.plist.template and bootstrap it. | header | +| InstallCodexUpdate.ts | installer | Materialize com.lifeos.codexupdate.plist.template and bootstrap it. | header | +| InstallCommitmentSweep.ts | installer | Materialize com.lifeos.commitmentsweep.plist.template and bootstrap. | header | +| InstallConveyorRunner.ts | installer | Materialize com.lifeos.conveyor-runner.plist.template and bootstrap it. | header | +| InstallConveyorWatcher.ts | installer | Materialize com.lifeos.conveyor-watcher.plist.template and bootstrap it. | header | +| InstallDerivedSync.ts | installer | Materialize com.lifeos.derivedsync.plist.template and bootstrap it. | header | +| InstallHealthSync.ts | installer | Materialize com.lifeos.healthsync.plist.template and bootstrap it. | header | +| InstallUsageAggregator.ts | installer | Materialize com.lifeos.usage-aggregator.plist.template | header | +| InstallWorkSweep.ts | installer | Materialize com.lifeos.worksweep.plist.template and bootstrap it. | header | +| IntegrityCheck.ts | cli | Full-system integrity orchestrator for the LifeOS system. | header | +| IntegrityMaintenance.ts | cli | Background script for system integrity and update documentation | header | +| InterviewIdealState.ts | cli | agenda tracker for seeding IDEAL_STATE + preference files. | header | +| InterviewScan.ts | cli | comprehensive completeness scanner across unified TELOS | header | +| IsaReconcile.ts | cli | Sweep every MEMORY/WORK//ISA.md and reconcile work.json. | header | +| ISARender.ts | cli | Render an ISA.md to a branded sibling ISA.html. | header | +| KnowledgeGraph.ts | cli | Associative graph navigation over LifeOS's knowledge archive | header | +| KnowledgeHarvester.ts | cli | Harvest knowledge from LifeOS memory into KNOWLEDGE/ | header | +| KnowledgeLint.ts | cli | validates the Knowledge Archive against the kb-v3 contract | header | +| KnowledgeQuery.ts | cli | the `kb query` surface over the Knowledge Archive. | header | +| KnowledgeSchema.ts | cli | the single source of truth for the LifeOS Knowledge Archive | header | +| LearningPatternSynthesis.ts | cli | Aggregate ratings into actionable patterns | header | +| lifeos.ts | cli | the LifeOS launcher CLI (aliased as `k`) | header | +| LifeosConfig.ts | cli | typed user-config loader. | header | +| LifeosLogo.ts | cli | — | header | +| LifeosUpgrade.ts | cli | idempotent migration runner + diagnostic harness for LifeOS rebuild. | header | +| LoadSkillConfig.ts | cli | Shared utility for loading skill configurations with user customizations | header | +| MemoryGraph.ts | cli | a first-class graph layer over the WHOLE LifeOS memory system. | header | +| MemoryHealthCheck.ts | cli | Autonomic memory subsystem health check. | header | +| MemoryInsights.ts | cli | `kai insights` CLI for autonomic memory delta view. | header | +| MemoryRestore.ts | cli | recover a hot-layer memory file from the per-write snapshot | header | +| MemoryRetriever.ts | cli | Compressed context retrieval over LifeOS's knowledge archive | header | +| MemoryReviewer.ts | cli | single-pass autonomic reviewer for the typed-item memory system. | header | +| MemoryStatus.ts | cli | read-only viewer for LifeOS's memory subsystem. | header | +| MemorySystem.ts | cli | single public API for the LifeOS memory subsystem. | header | +| MemoryTypes.ts | cli | frozen type registry for LifeOS's unified memory subsystem. | header | +| MemoryWriter.ts | cli | set-overwrite writer for PRINCIPAL_MEMORY.md / DA_MEMORY.md. | header | +| MergeSettings.ts | cli | — | header | +| MigrateApprove.ts | cli | review and commit proposed migration chunks from external | header | +| MigrateContextFreshness.ts | cli | adds pai-freshness-v1 frontmatter to constitutional | header | +| MigrateKnowledge.ts | cli | one-time (idempotent) migration of the Knowledge Archive | header | +| MigrateScan.ts | cli | intake content from external sources (other LifeOS installs, other | header | +| MigrateTelosFreshness.ts | cli | one-shot migration that adds the freshness convention | header | +| models.ts | cli | single source of truth for model IDs across LifeOS | header | +| MutationTier.ts | cli | four-tier autonomic-mutation boundary classifier. | header | +| NeofetchBanner.ts | cli | LifeOS System Banner in Neofetch Style | header | +| OpenRouter.ts | cli | frontier open-model access via the OpenRouter broker | header | +| PangramScore.ts | cli | score text for AI-detectability via the Pangram API. | header | +| PerplexitySearch.ts | cli | Perplexity Sonar API web research client | header | +| PipelineOrchestrator.ts | cli | — | header | +| PiSync.sh | cli | bring ~/.pi/agent/ in line with current ~/.claude/LIFEOS/ | header | +| PreviewMarkdown.ts | cli | — | header | +| ProposalGC.ts | cli | self-healing garbage collection for auto-appended memory proposals. | header | +| ProposeCurrentStateEntry.ts | cli | Pollers and _LIFELOG extractors enqueue proposals here. | header | +| Recommend.ts | cli | recency-aware picker for restaurants, movies, books. | header | +| ReferenceCheck.ts | cli | Full-surface reference validator for the LifeOS system. | header | +| RemoveBg.ts | cli | — | header | +| RetagSweepTypes.ts | cli | one-shot backfill of canonical Type:* labels onto the | header | +| SecretScan.ts | cli | Secret Scanning CLI | ~/.claude/skills/_LIFEOS/Workflows/SecretScanning.md | +| Services.ts | cli | the one-shot control surface for every LifeOS background service. | header | +| SessionHarvester.ts | cli | Extract learnings from Claude Code session transcripts | header | +| SessionProgress.ts | cli | — | header | +| SessionRename.ts | cli | rename a session in work.json and session-names.json. | header | +| SettingsBackport.ts | cli | propagate direct edits on the GENERATED settings.json | header | +| SplitAndTranscribe.ts | cli | — | header | +| SyncIdentityToSettings.ts | cli | Mirror PRINCIPAL_IDENTITY.md frontmatter | header | +| TelosFreshness.ts | cli | canonical reader/writer for TELOS staleness signal. | header | +| TlpArchive.ts | cli | scrape The Last Psychiatrist blog (thelastpsychiatrist.com) | header | +| ToolsRegistry.ts | cli | regenerate the flat-tool registry (FlatTools.md) from headers. | ~/.claude/LIFEOS/DOCUMENTATION/Tools/Tools.md | +| TranscriptParser.ts | cli | Claude transcript parsing utilities | header | +| UpdateLifeosState.ts | cli | Writes LIFEOS_STATE.json with per-dimension pct scores read by | header | +| UpdateModels.ts | cli | drift check + safe registry bump for model IDs | header | +| UsageAggregator.ts | cli | roll Claude Code usage into a DURABLE per-day store. | header | +| WisdomCrossFrameSynthesizer.ts | cli | Extract shared principles across Wisdom Frames | header | +| WisdomDomainClassifier.ts | cli | Route requests to relevant Wisdom Frames | header | +| WisdomFrameUpdater.ts | cli | Update Wisdom Frames with new observations | header | +| WorkSweep.ts | daemon | Periodic sweep that catches what event-driven hooks miss. | header | +| YouTubeApi.ts | cli | YouTube Data API v3 client | header | diff --git a/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md index 7b36349657..80d848e970 100755 --- a/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md +++ b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md @@ -913,6 +913,7 @@ MCP tool results are truncated by default. Servers can override this by adding ` ## Related Documentation +- **Flat-tool registry**: `~/.claude/LIFEOS/DOCUMENTATION/Tools/FlatTools.md` (generated — every tool in the `LIFEOS/TOOLS` root) - **Architecture**: `~/.claude/LIFEOS/DOCUMENTATION/LifeosSystemArchitecture.md` (master architecture reference) - **CLI Tools**: `~/.claude/LIFEOS/DOCUMENTATION/Tools/Cli.md` (Algorithm CLI, Arbol CLI) diff --git a/LifeOS/install/LIFEOS/TOOLS/ToolsRegistry.ts b/LifeOS/install/LIFEOS/TOOLS/ToolsRegistry.ts new file mode 100644 index 0000000000..43f5a8abb7 --- /dev/null +++ b/LifeOS/install/LIFEOS/TOOLS/ToolsRegistry.ts @@ -0,0 +1,68 @@ +#!/usr/bin/env bun +/** + * ToolsRegistry.ts — regenerate the flat-tool registry (FlatTools.md) from headers. + * + * Scans the LIFEOS/TOOLS root, parses each flat tool's leading header block + * against the element contract, and writes the generated registry table to + * DOCUMENTATION/Tools/FlatTools.md. The headers are the single source of + * truth; the registry is derived and never hand-edited. Deterministic output + * (no timestamps) — regeneration on an unchanged tree is a zero diff. + * + * Usage: + * bun ~/.claude/LIFEOS/TOOLS/ToolsRegistry.ts (write FlatTools.md) + * bun ~/.claude/LIFEOS/TOOLS/ToolsRegistry.ts --check (exit 1 + report if stale; writes nothing) + * bun ~/.claude/LIFEOS/TOOLS/ToolsRegistry.ts --stdout (print, write nothing) + * bun ~/.claude/LIFEOS/TOOLS/ToolsRegistry.ts --audit (per-file contract report for the whole tier) + * + * @see ~/.claude/LIFEOS/DOCUMENTATION/Tools/Tools.md + */ + +import { existsSync, readFileSync, writeFileSync } from 'fs'; +import { join } from 'path'; +import { getLifeosDir } from '../../hooks/lib/paths'; +import { + renderFlatTools, + listFlatTools, + parseFlatToolHeader, + checkHeaderContract, +} from '../../hooks/lib/flat-tool-header'; + +const LIFEOS = getLifeosDir(); +const TOOLS_ROOT = join(LIFEOS, 'TOOLS'); +const REGISTRY = join(LIFEOS, 'DOCUMENTATION', 'Tools', 'FlatTools.md'); + +const args = new Set(process.argv.slice(2)); + +if (args.has('--audit')) { + let bad = 0; + for (const f of listFlatTools(TOOLS_ROOT)) { + const header = parseFlatToolHeader(readFileSync(join(TOOLS_ROOT, f), 'utf-8'), f); + const missing = checkHeaderContract(header); + if (missing.length) { + bad++; + console.log(`${f}: missing ${missing.join(', ')}`); + } + } + console.log(bad === 0 ? 'audit: all flat tools contract-compliant' : `audit: ${bad} non-compliant`); + process.exit(bad === 0 ? 0 : 1); +} + +const rendered = renderFlatTools({ toolsRoot: TOOLS_ROOT }); + +if (args.has('--stdout')) { + console.log(rendered); + process.exit(0); +} + +if (args.has('--check')) { + const onDisk = existsSync(REGISTRY) ? readFileSync(REGISTRY, 'utf-8') : null; + if (onDisk === rendered) { + console.log('FlatTools.md: current'); + process.exit(0); + } + console.log(onDisk === null ? 'FlatTools.md: missing — run ToolsRegistry.ts' : 'FlatTools.md: stale — run ToolsRegistry.ts'); + process.exit(1); +} + +writeFileSync(REGISTRY, rendered); +console.log(`wrote ${REGISTRY}`); diff --git a/LifeOS/install/hooks/lib/flat-tool-header.ts b/LifeOS/install/hooks/lib/flat-tool-header.ts new file mode 100644 index 0000000000..d565c581ed --- /dev/null +++ b/LifeOS/install/hooks/lib/flat-tool-header.ts @@ -0,0 +1,207 @@ +/** + * flat-tool-header.ts — parser + registry renderer for the flat-tool tier + * + * PURPOSE: + * Single source of truth for reading a flat tool's leading header block and + * judging it against the element contract in `DOCUMENTATION/Tools/Tools.md` + * § Placement doctrine (identity line, purpose prose, usage-or-library-marked). + * Also renders the generated registry table (`DOCUMENTATION/Tools/FlatTools.md`). + * Consumed by `LIFEOS/TOOLS/ToolsRegistry.ts`. Pure functions, no side effects; + * the pointer element (@see) is judgment-scoped ("where a governing doc exists") + * and deliberately NOT machine-enforced. + * + * TRIGGER: n/a (shared lib — no stdin, no registration) + * + * USAGE: + * import { parseFlatToolHeader, checkHeaderContract, renderFlatTools } from './lib/flat-tool-header'; + */ + +import { readdirSync, readFileSync, statSync } from 'fs'; +import { join } from 'path'; + +export interface FlatHeader { + /** Leading doc-comment lines (shebang + env-preamble skipped). */ + headerLines: string[]; + style: 'jsdoc' | 'line' | 'none'; + /** `.ts — one-liner` (or ALL-CAPS banner) identity line, if found. */ + identity: string | null; + /** One-line purpose extracted from the identity line (text after the dash). */ + purpose: string | null; + hasUsage: boolean; + /** Header self-declares library shape ("not a CLI" / "Consumed by:"). */ + libMarked: boolean; + /** Header self-declares daemon shape (a `com.lifeos.*.plist` schedule). */ + daemonMarked: boolean; + /** First @see target, if any. */ + pointer: string | null; +} + +/** Regex-escape a filename stem for embedding. */ +const esc = (s: string): string => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + +/** + * Extract the leading header block: shebang skipped, the #1404 env-normalization + * preamble (comment + for-loop) skipped, comment blocks collected until the + * first real code line. + */ +export function parseFlatToolHeader(source: string, filename: string): FlatHeader { + const stem = filename.replace(/\.(ts|sh|py)$/, ''); + const hashComments = filename.endsWith('.sh') || filename.endsWith('.py'); + const lines = source.split('\n'); + const LIMIT = Math.min(lines.length, 80); + let i = 0; + if (lines[0]?.startsWith('#!')) i = 1; + + const blocks: string[][] = []; + let cur: string[] = []; + let sawJsdoc = false; + while (i < LIMIT) { + const l = lines[i].trim(); + if (l.startsWith('//') || (l.startsWith('#') && hashComments)) { + cur.push(l); + i++; + } else if (l.startsWith('/*') || (l.startsWith('"""') && filename.endsWith('.py'))) { + if (cur.length) { blocks.push(cur); cur = []; } + const close = l.startsWith('/*') ? '*/' : '"""'; + const js: string[] = []; + const first = i; + while (i < LIMIT) { + js.push(lines[i].trim()); + if (lines[i].includes(close) && !(i === first && lines[i].trim() === close)) { i++; break; } + i++; + } + blocks.push(js); + sawJsdoc = true; + } else if (l === '') { + if (cur.length) { blocks.push(cur); cur = []; } + i++; + } else if (/^for \(const __k of/.test(l)) { + if (cur.length) { blocks.push(cur); cur = []; } + let depth = (l.match(/\{/g) ?? []).length - (l.match(/\}/g) ?? []).length; + i++; + while (i < LIMIT && depth > 0) { + depth += (lines[i].match(/\{/g) ?? []).length - (lines[i].match(/\}/g) ?? []).length; + i++; + } + } else { + break; + } + } + if (cur.length) blocks.push(cur); + + const real = blocks.filter(b => !/Normalize env path vars/.test(b.join('\n'))); + const headerLines = real.flat(); + const h = headerLines.join('\n'); + const style: FlatHeader['style'] = headerLines.length === 0 ? 'none' : sawJsdoc ? 'jsdoc' : 'line'; + + const content = headerLines + .map(l => l.replace(/^\/\*+|\*+\/$|^\/\/+|^#+|^\*+/g, '').trim()) + .filter(l => l.length > 0); + + // Identity: a line leading with the stem + a dash separator, or an ALL-CAPS + // banner line naming the stem. An ASCII hyphen must be followed by a space, + // so a usage line (`algorithm -m loop …`) is not mistaken for the identity. + const sep = '(?:[—–]|-(?=\\s))\\s*'; + const idRe = new RegExp(`^${esc(stem)}(\\.(ts|sh|py))?\\s*${sep}`, 'i'); + const bannerRe = new RegExp(`^${esc(stem.toUpperCase())}\\b\\s*${sep}`); + let identity: string | null = null; + let purpose: string | null = null; + for (const l of content) { + const m = idRe.exec(l) ?? bannerRe.exec(l); + if (m) { + identity = l; + purpose = l.slice(m[0].length).trim() || null; + break; + } + } + + const hasUsage = + /USAGE\s*:/.test(h) || /Usage\s*:/i.test(h) || /Subcommands\s*:/i.test(h) || + /bun\s+\S*\.ts/.test(h) || new RegExp(`${esc(stem)}\\.(ts|sh|py)\\s+(\\w|<|\\[|-)`).test(h); + const libMarked = /not a CLI/i.test(h) || /Consumed by\s*:/i.test(h); + // A launchd-scheduled tool names its own plist in the header — either as an + // explicit `Trigger:` line or as prose ("Triggered by …com.lifeos.x.plist"). + const daemonMarked = /Trigger\s*:.*com\.lifeos\./i.test(h) || /com\.lifeos\.[\w.-]+\.plist/i.test(h); + const pointer = h.match(/@see\s+(\S+)/)?.[1] ?? null; + + return { headerLines, style, identity, purpose, hasUsage, libMarked, daemonMarked, pointer }; +} + +/** + * Machine-checkable subset of the element contract. Returns missing-element + * names; empty array = compliant. The @see pointer is not checked (requires + * judging whether a governing doc exists). + */ +export function checkHeaderContract(header: FlatHeader): string[] { + const missing: string[] = []; + if (!header.identity) missing.push('identity line'); + // Purpose prose: at least one content line beyond the identity line. + const prose = header.headerLines + .map(l => l.replace(/^\/\*+|\*+\/$|^\/\/+|^#+|^\*+/g, '').trim()) + .filter(l => l.length > 20); + if (header.identity && prose.length < 2) missing.push('purpose prose'); + if (!header.hasUsage && !header.libMarked) missing.push('usage (or library marker)'); + return missing; +} + +export interface RenderOptions { + /** Directory holding the flat tools. */ + toolsRoot: string; + /** Files exempt from the header-contract audit (still listed in the table). */ + deferred?: string[]; + /** Class overrides for files whose headers cannot carry a marker yet. */ + classOverrides?: Record; +} + +/** Enumerate the flat tier: root *.ts (excluding *.test.ts), *.sh and *.py. */ +export function listFlatTools(toolsRoot: string): string[] { + return readdirSync(toolsRoot) + .filter(f => /\.(ts|sh|py)$/.test(f) && !f.endsWith('.test.ts')) + .filter(f => { + try { return statSync(join(toolsRoot, f)).isFile(); } catch { return false; } + }) + .sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' })); +} + +/** Class a flat tool from what its own header declares. */ +export function classifyFlatTool(filename: string, header: FlatHeader): string { + if (filename.startsWith('Install')) return 'installer'; + if (header.daemonMarked) return 'daemon'; + if (header.libMarked) return header.hasUsage ? 'dual' : 'library'; + return 'cli'; +} + +/** Render the FlatTools.md registry. Deterministic: no timestamps. */ +export function renderFlatTools(opts: RenderOptions): string { + const deferred = new Set(opts.deferred ?? []); + const overrides = opts.classOverrides ?? {}; + + const rows: string[] = []; + let gaps = 0; + for (const f of listFlatTools(opts.toolsRoot)) { + const header = parseFlatToolHeader(readFileSync(join(opts.toolsRoot, f), 'utf-8'), f); + if (!deferred.has(f) && checkHeaderContract(header).length) gaps++; + const cls = overrides[f] ?? classifyFlatTool(f, header); + const purpose = (header.purpose ?? '—').replace(/\|/g, '\\|'); + const docs = header.pointer ? header.pointer.replace(/\|/g, '\\|') : 'header'; + rows.push(`| ${f} | ${cls} | ${purpose} | ${docs} |`); + } + + const gapLine = gaps === 0 + ? 'Every header meets the element contract.' + : `${gaps} header${gaps === 1 ? '' : 's'} short of the element contract — \`ToolsRegistry.ts --audit\` lists them.`; + + return [ + '# Flat Tools — generated registry', + '', + '> Generated by `LIFEOS/TOOLS/ToolsRegistry.ts` from the tools\' own headers — do not hand-edit.', + '> Regenerate: `bun ~/.claude/LIFEOS/TOOLS/ToolsRegistry.ts`. Contract: `Tools.md` § Placement doctrine.', + '', + `${rows.length} tools in the LIFEOS/TOOLS root. ${gapLine}`, + '', + '| Tool | Class | Purpose | Docs |', + '|---|---|---|---|', + ...rows, + '', + ].join('\n'); +} From 1218fa7807fbe6e5f10ff5c74719ced637a5993f Mon Sep 17 00:00:00 2001 From: alex anikin <60673011+anikinsasha@users.noreply.github.com> Date: Thu, 30 Jul 2026 00:05:06 -0700 Subject: [PATCH 5/5] docs(tools): relocate the two sections that are not tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SECONDARY — separately reviewable, and droppable without touching the rest of this PR. The placement doctrine says HTTP routes belong to the owning subsystem's doc and Claude Code harness primitives belong to DelegationSystem.md. Two sections in Tools.md were on the wrong side of that line, so this applies the rule to the file that states it. Nothing is deleted — both sections move whole: Voice Server API (~44 lines) -> NotificationSystem.md § Long-form Narration. /notify is a Pulse route, and NotificationSystem.md already documented the same endpoint for notifications; the narration triggers, tuning values and 450-char segment rule join it there. Monitor + 6 recipes (~90 lines) -> DelegationSystem.md § Async Primitives. Monitor is a harness primitive this repo does not ship. Async Primitives already carried the Monitor rules nearly verbatim, so only the recipe cookbook is new content there; the duplicated rule list is dropped rather than moved twice. Tools.md keeps a one-line stub at each site pointing to the new home, so a reader who goes looking where the section used to be still lands correctly. The Research-skill cross-reference is repointed too. --- .../Delegation/DelegationSystem.md | 81 +++++++++++ .../Notifications/NotificationSystem.md | 29 ++++ .../LIFEOS/DOCUMENTATION/Tools/Tools.md | 136 +----------------- 3 files changed, 115 insertions(+), 131 deletions(-) diff --git a/LifeOS/install/LIFEOS/DOCUMENTATION/Delegation/DelegationSystem.md b/LifeOS/install/LIFEOS/DOCUMENTATION/Delegation/DelegationSystem.md index 10a4796738..3ed38fc7a0 100755 --- a/LifeOS/install/LIFEOS/DOCUMENTATION/Delegation/DelegationSystem.md +++ b/LifeOS/install/LIFEOS/DOCUMENTATION/Delegation/DelegationSystem.md @@ -198,6 +198,87 @@ Three primitives for non-blocking work. Pick the right one: - Use `TaskStop` to cancel a monitor early - Selective filters only — never pipe raw logs. Monitors producing too many events get auto-stopped. +### Recipe: Agent Watchdog (auto-triggered by hook) + +The Pulse agent-guard hook automatically injects a watchdog reminder when background agents are spawned. The watchdog monitors tool-activity.jsonl for silence while agents are active: + +```bash +Monitor({ + description: "Agent watchdog", + persistent: true, + timeout_ms: 3600000, + command: "bun $HOME/.claude/LIFEOS/TOOLS/AgentWatchdog.ts" +}) +``` + +Alerts when no tool calls detected for 90 seconds with active agents. Rate-limited to one alert per 60 seconds. Runs for the session lifetime — covers all background agents. + +### Recipe: Deploy Monitoring + +Watch a Cloudflare Pages or Workers deploy for completion or errors: + +```bash +# Monitor wrangler deploy output (run deploy with Bash(run_in_background), then tail its output) +Monitor({ + description: "Cloudflare deploy status", + persistent: false, + timeout_ms: 300000, + command: "tail -f /tmp/deploy.log | grep --line-buffered -E '(Published|Error|Failed|SUCCESS)'" +}) +``` + +### Recipe: Pulse Log Tailing + +Watch Pulse daemon logs for errors during a debugging session: + +```bash +Monitor({ + description: "Pulse error watcher", + persistent: true, + timeout_ms: 300000, + command: "tail -f ~/.claude/Pulse/logs/pulse-stdout.log | grep --line-buffered -i -E '(error|fatal|crash|unhandled)'" +}) +``` + +### Recipe: Build/Test Watching + +Monitor a long test suite and get notified on failures: + +```bash +Monitor({ + description: "Test failure watcher", + persistent: false, + timeout_ms: 600000, + command: "tail -f /tmp/test-output.log | grep --line-buffered -E '(FAIL|ERROR|✗|AssertionError)'" +}) +``` + +### Recipe: PR/CI Status Monitoring + +Poll GitHub for CI status changes on a PR: + +```bash +Monitor({ + description: "CI status for PR #42", + persistent: true, + timeout_ms: 3600000, + command: "last_status=''; while true; do status=$(gh pr checks 42 --json state --jq '.[].state' 2>/dev/null | sort -u | tr '\\n' ','); if [ \"$status\" != \"$last_status\" ]; then echo \"CI: $status\"; last_status=\"$status\"; fi; sleep 30; done" +}) +``` + +### Recipe: Security Scan Watching + +Tail security scan results for critical findings: + +```bash +Monitor({ + description: "Security scan critical findings", + persistent: false, + timeout_ms: 600000, + command: "tail -f /tmp/security-scan.log | grep --line-buffered -i 'CRITICAL'" +}) +``` + --- ## Knowledge Archive Access diff --git a/LifeOS/install/LIFEOS/DOCUMENTATION/Notifications/NotificationSystem.md b/LifeOS/install/LIFEOS/DOCUMENTATION/Notifications/NotificationSystem.md index 19b722380a..4c4cb46e60 100755 --- a/LifeOS/install/LIFEOS/DOCUMENTATION/Notifications/NotificationSystem.md +++ b/LifeOS/install/LIFEOS/DOCUMENTATION/Notifications/NotificationSystem.md @@ -124,6 +124,35 @@ curl -s -X POST http://localhost:31337/notify \ --- +## Long-form Narration + +The same `/notify` endpoint reads longer text aloud — "read this to me", "narrate this", "speak this", "perform this". It is a Pulse route, not a callable tool, so it lives here rather than in the tool index. + +```bash +# Single narration segment +curl -X POST http://localhost:31337/notify \ + -H "Content-Type: application/json" \ + -d '{ + "message": "Your text here", + "voice_id": "$ELEVENLABS_VOICE_ID", + "title": "Voice Narrative" + }' + +# Pause between segments +sleep 2 +``` + +**Narration settings:** +- **Voice ID:** `ELEVENLABS_VOICE_ID` environment variable +- **Stability:** 0.55 (natural variation in storytelling) +- **Similarity Boost:** 0.85 (maintains authentic sound) +- **Max segment:** 450 characters — split longer text +- **Pause between:** 2 seconds, for storytelling flow + +Pulse must be running; the voice handler lives at `~/.claude/LIFEOS/PULSE/VoiceServer/voice.ts` on port 31337, and calls ElevenLabs under the hood. + +--- + ## Copy-Paste Templates ### Template A: Skills WITH Workflows diff --git a/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md index 80d848e970..621565e8c7 100755 --- a/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md +++ b/LifeOS/install/LIFEOS/DOCUMENTATION/Tools/Tools.md @@ -323,47 +323,9 @@ bun ~/.claude/LIFEOS/TOOLS/KnowledgeGraph.ts find architecture --- -## Voice Server API - Generate Voice Narration +## Voice narration — not a tool -**Location:** Voice server at `http://localhost:31337/notify` - -Send text to the voice server running on localhost for TTS using a configured voice clone. - -**Usage:** -```bash -# Single narration segment -curl -X POST http://localhost:31337/notify \ - -H "Content-Type: application/json" \ - -d '{ - "message": "Your text here", - "voice_id": "$ELEVENLABS_VOICE_ID", - "title": "Voice Narrative" - }' - -# Pause between segments -sleep 2 -``` - -**Voice Configuration:** -- **Voice ID:** Set via `ELEVENLABS_VOICE_ID` environment variable -- **Stability:** 0.55 (natural variation in storytelling) -- **Similarity Boost:** 0.85 (maintains authentic sound) -- **Server:** `http://localhost:31337/notify` -- **Max Segment:** 450 characters -- **Pause Between:** 2 seconds - -**When to Use:** -- "read this to me" -- "voice narrative" -- "speak this" -- "narrate this" -- "perform this" - -**Technical Details:** -- Pulse must be running (voice handler lives at `~/.claude/LIFEOS/PULSE/VoiceServer/voice.ts`, port 31337) -- Segments longer than 450 chars should be split -- Natural 2-second pauses between segments for storytelling flow -- Uses ElevenLabs API under the hood +`POST localhost:31337/notify` is a Pulse route, not a callable tool. Narration triggers, payload, and the tuning knobs live in `../Notifications/NotificationSystem.md` § Long-form Narration. --- @@ -564,97 +526,9 @@ rtk verify # Check installation integrity --- -## Monitor Tool — Event-Driven Background Watching - -The Monitor tool starts a background script whose stdout lines become chat notifications. Instead of polling in a loop (burning tokens), the script runs independently and wakes you when something happens. Zero token cost between events. - -**Key rules:** -- Each stdout line = one notification. Stderr goes to output file only. -- Always use `grep --line-buffered` in pipes (otherwise pipe buffering delays events). -- Poll intervals: 30s+ for remote APIs, 0.5-1s for local checks. -- Handle transient failures: `curl ... || true` in poll loops. -- Set `persistent: true` for session-length watches. Cancel with `TaskStop`. - -### Recipe: Agent Watchdog (auto-triggered by hook) - -The Pulse agent-guard hook automatically injects a watchdog reminder when background agents are spawned. The watchdog monitors tool-activity.jsonl for silence while agents are active: - -```bash -Monitor({ - description: "Agent watchdog", - persistent: true, - timeout_ms: 3600000, - command: "bun $HOME/.claude/LIFEOS/TOOLS/AgentWatchdog.ts" -}) -``` - -Alerts when no tool calls detected for 90 seconds with active agents. Rate-limited to one alert per 60 seconds. Runs for the session lifetime — covers all background agents. - -### Recipe: Deploy Monitoring - -Watch a Cloudflare Pages or Workers deploy for completion or errors: - -```bash -# Monitor wrangler deploy output (run deploy with Bash(run_in_background), then tail its output) -Monitor({ - description: "Cloudflare deploy status", - persistent: false, - timeout_ms: 300000, - command: "tail -f /tmp/deploy.log | grep --line-buffered -E '(Published|Error|Failed|SUCCESS)'" -}) -``` - -### Recipe: Pulse Log Tailing +## Monitor — not a tool -Watch Pulse daemon logs for errors during a debugging session: - -```bash -Monitor({ - description: "Pulse error watcher", - persistent: true, - timeout_ms: 300000, - command: "tail -f ~/.claude/Pulse/logs/pulse-stdout.log | grep --line-buffered -i -E '(error|fatal|crash|unhandled)'" -}) -``` - -### Recipe: Build/Test Watching - -Monitor a long test suite and get notified on failures: - -```bash -Monitor({ - description: "Test failure watcher", - persistent: false, - timeout_ms: 600000, - command: "tail -f /tmp/test-output.log | grep --line-buffered -E '(FAIL|ERROR|✗|AssertionError)'" -}) -``` - -### Recipe: PR/CI Status Monitoring - -Poll GitHub for CI status changes on a PR: - -```bash -Monitor({ - description: "CI status for PR #42", - persistent: true, - timeout_ms: 3600000, - command: "last_status=''; while true; do status=$(gh pr checks 42 --json state --jq '.[].state' 2>/dev/null | sort -u | tr '\\n' ','); if [ \"$status\" != \"$last_status\" ]; then echo \"CI: $status\"; last_status=\"$status\"; fi; sleep 30; done" -}) -``` - -### Recipe: Security Scan Watching - -Tail security scan results for critical findings: - -```bash -Monitor({ - description: "Security scan critical findings", - persistent: false, - timeout_ms: 600000, - command: "tail -f /tmp/security-scan.log | grep --line-buffered -i 'CRITICAL'" -}) -``` +`Monitor` is a Claude Code harness primitive, not something this repo ships. The rules, the pick-your-primitive table, and the recipe cookbook live in `../Delegation/DelegationSystem.md` § Async Primitives. --- @@ -671,7 +545,7 @@ Monitor({ ### Research Skill - YouTube transcripts: `GetTranscript.ts` - Audio/video transcription: `extract-transcript.py` -- Voice narration: Voice server API +- Voice narration: `../Notifications/NotificationSystem.md` § Long-form Narration ### Metrics Skill - YouTube analytics: `YouTubeApi.ts`