From 533438178fbe8038a2986879aec5dcec7df679b2 Mon Sep 17 00:00:00 2001 From: Val Alexander <68980965+BunsDev@users.noreply.github.com> Date: Sun, 24 May 2026 05:29:56 -0500 Subject: [PATCH] docs: add harness deep dives --- content/docs/familiars/harnesses.mdx | 2 + content/docs/harnesses/claude-code.mdx | 69 +++++++++++ content/docs/harnesses/codex.mdx | 69 +++++++++++ content/docs/harnesses/custom-adapters.mdx | 45 +++++++ content/docs/harnesses/index.mdx | 58 +++++++++ content/docs/harnesses/installing.mdx | 67 ++++++++++ content/docs/harnesses/meta.json | 18 +++ content/docs/harnesses/project-roots.mdx | 46 +++++++ content/docs/harnesses/provider-auth.mdx | 49 ++++++++ content/docs/harnesses/troubleshooting.mdx | 45 +++++++ content/docs/harnesses/what-is-a-harness.mdx | 52 ++++++++ .../docs/harnesses/working-directories.mdx | 43 +++++++ content/docs/meta.json | 2 +- package.json | 3 +- scripts/check-harness-docs.mjs | 114 ++++++++++++++++++ 15 files changed, 680 insertions(+), 2 deletions(-) create mode 100644 content/docs/harnesses/claude-code.mdx create mode 100644 content/docs/harnesses/codex.mdx create mode 100644 content/docs/harnesses/custom-adapters.mdx create mode 100644 content/docs/harnesses/index.mdx create mode 100644 content/docs/harnesses/installing.mdx create mode 100644 content/docs/harnesses/meta.json create mode 100644 content/docs/harnesses/project-roots.mdx create mode 100644 content/docs/harnesses/provider-auth.mdx create mode 100644 content/docs/harnesses/troubleshooting.mdx create mode 100644 content/docs/harnesses/what-is-a-harness.mdx create mode 100644 content/docs/harnesses/working-directories.mdx create mode 100644 scripts/check-harness-docs.mjs diff --git a/content/docs/familiars/harnesses.mdx b/content/docs/familiars/harnesses.mdx index 2d54010..b8be612 100644 --- a/content/docs/familiars/harnesses.mdx +++ b/content/docs/familiars/harnesses.mdx @@ -10,6 +10,8 @@ import { Mermaid } from '@/components/mermaid'; Coven v0 supports Codex and Claude Code. This guide describes the current adapter shape and the bar for adding more harnesses. +For install, provider-auth, project-root, and per-harness operational details, see the first-class [Harnesses deep dives](/docs/harnesses/what-is-a-harness). + ## Current Adapter Shape A built-in harness adapter defines a compact launch contract. diff --git a/content/docs/harnesses/claude-code.mdx b/content/docs/harnesses/claude-code.mdx new file mode 100644 index 0000000..b0af749 --- /dev/null +++ b/content/docs/harnesses/claude-code.mdx @@ -0,0 +1,69 @@ +--- +title: "Claude Code Harness" +summary: "Run Anthropic Claude Code under Coven supervision with harness id claude." +description: "Claude Code harness deep dive: setup, provider auth, launch arguments, project-root behavior, and troubleshooting." +read_when: + - Setting up Claude Code for Coven + - Diagnosing Claude-specific launch or auth failures +--- + +import { Mermaid } from '@/components/mermaid'; + +# Claude Code Harness + +Claude Code is Anthropic's coding-agent CLI. Coven launches it as a project-rooted PTY and records the run as a Coven session. + +| Field | Value | +| --- | --- | +| Harness id | `claude` | +| Executable | `claude` | +| Install | `npm install -g @anthropic-ai/claude-code` | +| Provider auth | `claude doctor` | +| First run | `coven run claude "polish this UI"` | + +## Setup + +```bash +npm install -g @anthropic-ai/claude-code +claude doctor +coven doctor +``` + +`coven doctor` checks that `claude` is available on `PATH`. It does not read Anthropic credentials. + +## Launch + +```bash +coven run claude "refactor this component" --cwd packages/web --title "Web refactor" +``` + +In interactive terminals, Coven launches Claude Code with the prompt as the final argument. In non-interactive mode, Coven uses Claude Code's `--print` shape so output can be captured by callers. + +## Supervision flow + +>C: coven run claude "polish this UI" + C->>D: Launch session request + D->>D: validate harness id, project root, cwd + D->>L: spawn claude in PTY + L->>A: provider auth and model calls + L-->>D: stdout, stderr, exit + D-->>C: session id and status +`} /> + +## Common failures + +| Symptom | Likely cause | Fix | +| --- | --- | --- | +| `coven doctor` reports Claude Code missing | `claude` is not on daemon `PATH` | Install Claude Code, restart daemon, rerun doctor. | +| Claude prompts for setup | Provider auth is incomplete | Run `claude doctor`. | +| Launch rejects cwd | `--cwd` escapes the project root | Use a cwd inside the project. | + +For shared setup rules, see [Install harness CLIs](/docs/harnesses/installing) and [Provider auth boundary](/docs/harnesses/provider-auth). diff --git a/content/docs/harnesses/codex.mdx b/content/docs/harnesses/codex.mdx new file mode 100644 index 0000000..57fbfa1 --- /dev/null +++ b/content/docs/harnesses/codex.mdx @@ -0,0 +1,69 @@ +--- +title: "Codex Harness" +summary: "Run OpenAI Codex CLI under Coven supervision with harness id codex." +description: "Codex harness deep dive: setup, provider auth, launch arguments, project-root behavior, and troubleshooting." +read_when: + - Setting up Codex for Coven + - Diagnosing Codex-specific launch or auth failures +--- + +import { Mermaid } from '@/components/mermaid'; + +# Codex Harness + +Codex is OpenAI's coding-agent CLI. Coven launches it as a project-rooted PTY and records the run as a Coven session. + +| Field | Value | +| --- | --- | +| Harness id | `codex` | +| Executable | `codex` | +| Install | `npm install -g @openai/codex` | +| Provider auth | `codex login` | +| First run | `coven run codex "fix the failing tests"` | + +## Setup + +```bash +npm install -g @openai/codex +codex login +coven doctor +``` + +`coven doctor` checks that `codex` is available on `PATH`. It does not read Codex's OpenAI credentials. + +## Launch + +```bash +coven run codex "audit this repo" --cwd packages/cli --title "CLI audit" +``` + +In interactive terminals, Coven launches Codex with the prompt as the final argument. In non-interactive mode, Coven uses Codex's `exec --skip-git-repo-check --color never` shape so output is easier to capture. + +## Supervision flow + +>C: coven run codex "audit this repo" + C->>D: Launch session request + D->>D: validate harness id, project root, cwd + D->>X: spawn codex in PTY + X->>O: provider auth and model calls + X-->>D: stdout, stderr, exit + D-->>C: session id and status +`} /> + +## Common failures + +| Symptom | Likely cause | Fix | +| --- | --- | --- | +| `coven doctor` reports Codex missing | `codex` is not on daemon `PATH` | Install Codex, restart daemon, rerun doctor. | +| Codex asks for login | OAuth state expired or missing | Run `codex login`. | +| Launch rejects cwd | `--cwd` escapes the project root | Use a cwd inside the project. | + +For shared setup rules, see [Install harness CLIs](/docs/harnesses/installing) and [Provider auth boundary](/docs/harnesses/provider-auth). diff --git a/content/docs/harnesses/custom-adapters.mdx b/content/docs/harnesses/custom-adapters.mdx new file mode 100644 index 0000000..0d47dcb --- /dev/null +++ b/content/docs/harnesses/custom-adapters.mdx @@ -0,0 +1,45 @@ +--- +title: "Custom Adapters" +summary: "The adapter bar for future harnesses: stable ids, fixed argv, PATH detection, provider-auth separation, and daemon validation." +description: "Guidance for adding future Coven harness adapters without weakening daemon authority or provider credential boundaries." +read_when: + - Evaluating a future harness integration + - Reviewing whether a custom adapter belongs in Coven +--- + +# Custom Adapters + +Coven v0 ships built-in adapters for Codex and Claude Code. Future adapters should meet the same bar before they are documented as supported. + +## Adapter contract + +An adapter needs: + +| Field | Meaning | +| --- | --- | +| Stable `Harness id` | The id clients pass to `coven run` and the socket API. | +| Label | Human-readable display name. | +| Executable | Binary name resolved on `PATH`; not an arbitrary client-supplied path. | +| Interactive prompt args | Fixed argv prefix for terminal sessions. | +| Non-interactive prompt args | Fixed argv prefix for scripts and output capture. | +| Install hint | Actionable setup text for `coven doctor`. | + +The prompt should be the final argument after any fixed prefix args unless the adapter design explicitly proves a different shape is safer. + +## Review checklist + +Before adding a new adapter, verify: + +- The CLI can run inside a normal PTY. +- It has a stable command-line prompt shape. +- It can run from an explicit working directory. +- Provider credentials stay with the harness. +- It has a clear install/auth story. +- It does not require clients to pass secrets through Coven. +- It can fail closed when the executable is missing. + +## Planned does not mean supported + +Hermes, Aider, Gemini CLI, Cline, and other runtimes may become useful future harnesses. Until they land in the adapter table and `coven doctor`, docs should describe them as roadmap or design work, not current support. + +For current commands, use [Codex](/docs/harnesses/codex), [Claude Code](/docs/harnesses/claude-code), and [CLI run reference](/docs/cli/run). diff --git a/content/docs/harnesses/index.mdx b/content/docs/harnesses/index.mdx new file mode 100644 index 0000000..d7033b4 --- /dev/null +++ b/content/docs/harnesses/index.mdx @@ -0,0 +1,58 @@ +--- +title: "Harnesses" +summary: "Harnesses are external coding-agent CLIs that Coven launches, supervises, records, and exposes through project-scoped sessions." +description: "Overview of Coven harnesses, supported v0 adapters, provider-auth boundaries, project-root rules, and adapter direction." +read_when: + - Choosing whether to run Codex or Claude Code through Coven + - Explaining the difference between a harness, a familiar, and the daemon +--- + +import { Mermaid } from '@/components/mermaid'; + +# Harnesses + +A harness is an external coding-agent CLI that Coven can launch inside a project root. Coven owns the PTY, session record, event log, attach/replay flow, and local API boundary. The harness owns the conversation, provider authentication, and tool execution inside its own process. + +The current v0 harness ids are `codex` and `claude`. + +## Supported v0 harnesses + +| Harness | Harness id | Executable | First command | +| --- | --- | --- | --- | +| Codex | `codex` | `codex` | `coven run codex "fix the failing tests"` | +| Claude Code | `claude` | `claude` | `coven run claude "polish this UI"` | + +## Runtime boundary + + CLI[coven CLI / API client] + CLI --> Daemon[Coven daemon] + Daemon --> Adapter[Harness adapter table] + Adapter --> Codex[Codex PTY] + Adapter --> Claude[Claude Code PTY] + Codex --> OpenAI[OpenAI provider auth] + Claude --> Anthropic[Anthropic provider auth] + Daemon --> Ledger[(SQLite sessions + events)] + + style Daemon fill:#9A8ECD,stroke:#D4B5FF,color:#1A1825 + style Adapter fill:#3D3547,stroke:#9A8ECD,color:#fff +`} /> + +The daemon validates the harness id, project root, working directory, session id, live-session state, and control actions. It does not read provider credentials and does not become the provider client. + +## Read next + +- [What is a harness?](/docs/harnesses/what-is-a-harness) for the concept boundary. +- [Install harness CLIs](/docs/harnesses/installing) for Codex and Claude Code setup. +- [Provider auth boundary](/docs/harnesses/provider-auth) before auditing credentials. +- [Project roots](/docs/harnesses/project-roots) and [working directories](/docs/harnesses/working-directories) before debugging launch rejects. +- [Codex](/docs/harnesses/codex) and [Claude Code](/docs/harnesses/claude-code) for adapter-specific behavior. +- [Custom adapters](/docs/harnesses/custom-adapters) for the future adapter bar. +- [Troubleshooting](/docs/harnesses/troubleshooting) when `coven doctor` or `coven run` fails. + +## Related + +- [CLI run reference](/docs/cli/run) +- [Session lifecycle](/docs/familiars/sessions) +- [Daemon security posture](/docs/daemon/security) diff --git a/content/docs/harnesses/installing.mdx b/content/docs/harnesses/installing.mdx new file mode 100644 index 0000000..e90b9b2 --- /dev/null +++ b/content/docs/harnesses/installing.mdx @@ -0,0 +1,67 @@ +--- +title: "Install Harness CLIs" +summary: "Coven detects external harness CLIs on PATH and fails closed with setup hints when they are missing." +description: "How to install Codex and Claude Code for Coven, how detection works, and how to recover from PATH or auth setup problems." +read_when: + - Setting up a new machine for Coven + - Resolving missing harness errors from coven doctor +--- + +import { Mermaid } from '@/components/mermaid'; + +# Install Harness CLIs + +Coven does not bundle harness CLIs. Each harness is installed and authenticated through its own provider's tooling, then Coven detects the executable on `PATH`. + +## Supported v0 harnesses + +| Harness id | Executable | Install command | Provider login | +| --- | --- | --- | --- | +| `codex` | `codex` | `npm install -g @openai/codex` | `codex login` | +| `claude` | `claude` | `npm install -g @anthropic-ai/claude-code` | `claude doctor` | + +After installing, run: + +```bash +coven doctor +``` + +`coven doctor` reports whether the executable is available. It does not read provider credentials; the login command remains provider-owned. + +## Detection flow + + Lookup{Known harness id?} + Lookup -- no --> RejectUnsupported[Reject unsupported harness] + Lookup -- yes --> Path{Executable on PATH?} + Path -- no --> Hint[Fail closed with install hint] + Path -- yes --> Spawn[Spawn fixed adapter argv in PTY] +`} /> + +Only built-in harness ids are accepted. A client cannot send an arbitrary executable path through the daemon API. + +## PATH and daemon environment + +If you install a harness after the daemon is already running, restart the daemon so the process environment is fresh: + +```bash +coven daemon restart +coven doctor +``` + +If `coven doctor` still reports a missing harness, check duplicate or unexpected binaries: + +```bash +which -a codex +which -a claude +``` + +## First launch + +```bash +coven run codex "describe this project" +coven run claude "review this project for risky defaults" +``` + +Use [Provider auth boundary](/docs/harnesses/provider-auth) if a harness launches but exits with a provider login error. diff --git a/content/docs/harnesses/meta.json b/content/docs/harnesses/meta.json new file mode 100644 index 0000000..d97196e --- /dev/null +++ b/content/docs/harnesses/meta.json @@ -0,0 +1,18 @@ +{ + "title": "Harnesses", + "description": "Deep dives for Codex, Claude Code, provider auth, project roots, working directories, and adapter boundaries.", + "root": true, + "icon": "LuCable", + "pages": [ + "index", + "what-is-a-harness", + "installing", + "provider-auth", + "project-roots", + "working-directories", + "codex", + "claude-code", + "custom-adapters", + "troubleshooting" + ] +} diff --git a/content/docs/harnesses/project-roots.mdx b/content/docs/harnesses/project-roots.mdx new file mode 100644 index 0000000..b637176 --- /dev/null +++ b/content/docs/harnesses/project-roots.mdx @@ -0,0 +1,46 @@ +--- +title: "Project Roots" +summary: "Every harness session is pinned to a canonical project root before Coven launches the PTY." +description: "How Coven resolves project roots for harness sessions and why launch requests cannot widen the project boundary." +read_when: + - A launch fails because Coven cannot resolve the project + - You are building a client that sends project-rooted session requests +--- + +# Project Roots + +Every harness session starts from a project root. Coven resolves and canonicalizes that root before it launches a PTY or records the session. + +## Why it matters + +Project roots make sessions auditable. A session record can answer: + +- Which repository or project was the work tied to? +- Which harness id ran? +- Which working directory did the process start in? +- Which event log belongs to that run? + +Without a project root, a harness run is just a loose process. Coven's job is to make it a named, reviewable session. + +## CLI behavior + +Run from inside a project: + +```bash +cd /path/to/project +coven run codex "fix the failing tests" +``` + +If Coven cannot resolve a project root, `coven doctor` and `coven run` give setup evidence instead of launching a vague process. + +## Client behavior + +Clients should treat project root as authority-sensitive input. They can collect and display it, but the daemon still validates it. + +Do not trust a browser or chat client to enforce project boundaries on its own. The daemon remains the validation boundary described in [Daemon security posture](/docs/daemon/security). + +## Related + +- [Working directories](/docs/harnesses/working-directories) +- [CLI run reference](/docs/cli/run) +- [Session lifecycle](/docs/familiars/sessions) diff --git a/content/docs/harnesses/provider-auth.mdx b/content/docs/harnesses/provider-auth.mdx new file mode 100644 index 0000000..9f3d922 --- /dev/null +++ b/content/docs/harnesses/provider-auth.mdx @@ -0,0 +1,49 @@ +--- +title: "Provider Auth Boundary" +summary: "Provider credentials stay with each harness CLI. Coven never stores, proxies, or mints provider tokens." +description: "Security boundary for OpenAI, Anthropic, and future provider credentials when running harnesses through Coven." +read_when: + - Auditing where OpenAI or Anthropic credentials live + - Deciding whether a client should send provider tokens to Coven +--- + +import { Mermaid } from '@/components/mermaid'; + +# Provider Auth Boundary + +Provider credentials stay with the harness. Coven supervises a PTY; it does not become OpenAI, Anthropic, or any future provider's credential layer. + +## Rule + +Coven never stores, proxies, persists, or mints provider credentials. + +| Harness id | Login command | Credential owner | +| --- | --- | --- | +| `codex` | `codex login` | Codex CLI and OpenAI's local auth flow | +| `claude` | `claude doctor` | Claude Code and Anthropic's local auth flow | + +## Credential path + + Login["codex login / claude doctor"] + Login --> Store[(Provider credential store)] + User --> Run["coven run codex prompt"] + Run --> Daemon[Coven daemon] + Daemon --> Pty[Harness PTY] + Pty --> Store + Pty --> Provider[Provider API] + Daemon -. never reads .-> Store +`} /> + +The missing arrow is the important part: the daemon does not read the provider credential store. + +## What the daemon sees + +The daemon sees PTY output and process exits. If the harness prints an auth error, Coven records that output like any other session output. If a user asks a harness to print a secret, that output can land in the event log. This is a user-side safety rule, not provider-token support in Coven. + +## What clients must not do + +Clients should not add provider-token fields to Coven requests. The socket API does not need API keys, OAuth refresh tokens, bearer tokens, or account ids to launch a session. + +Use [Authentication and local access](/docs/reference/auth) for the daemon access model and [Daemon security posture](/docs/daemon/security) for the local trust boundary. diff --git a/content/docs/harnesses/troubleshooting.mdx b/content/docs/harnesses/troubleshooting.mdx new file mode 100644 index 0000000..0b71b35 --- /dev/null +++ b/content/docs/harnesses/troubleshooting.mdx @@ -0,0 +1,45 @@ +--- +title: "Harness Troubleshooting" +summary: "Diagnose missing harnesses, provider-auth failures, cwd rejects, PTY exits, and stale daemon environment." +description: "Troubleshooting guide for Coven harness adapters and session launches." +read_when: + - coven run fails + - coven doctor reports missing harnesses +--- + +# Harness Troubleshooting + +Start with: + +```bash +coven doctor +``` + +The doctor output tells you whether Coven can see the store, project, daemon, socket, and harness executables. See [Doctor](/docs/cli/doctor) for how to read it. + +## Fast triage + +| Symptom | Likely cause | Fix | +| --- | --- | --- | +| Harness is `missing` | Binary is not on daemon `PATH` | Install it, restart daemon, rerun `coven doctor`. | +| `unsupported harness` | Wrong harness id | Use `codex` or `claude`. | +| Provider login prompt or auth error | Harness credentials are missing or expired | Run `codex login` or `claude doctor`. | +| cwd validation error | Working directory escapes project root | Use a cwd inside the project. | +| Session exits immediately | Harness CLI failed before work began | Attach or inspect events, then run the harness directly once. | +| Client works differently than terminal | Daemon environment is stale | `coven daemon restart`, then retry. | + +## Evidence to collect + +```bash +coven doctor +coven daemon status +coven sessions --all --plain +``` + +If a specific session failed, use: + +```bash +coven attach +``` + +For daemon-specific state, continue with [Daemon observability](/docs/daemon/observability). For provider auth, continue with [Provider auth boundary](/docs/harnesses/provider-auth). diff --git a/content/docs/harnesses/what-is-a-harness.mdx b/content/docs/harnesses/what-is-a-harness.mdx new file mode 100644 index 0000000..de1ed10 --- /dev/null +++ b/content/docs/harnesses/what-is-a-harness.mdx @@ -0,0 +1,52 @@ +--- +title: "What Is a Harness?" +summary: "A harness is a PTY-driven adapter for one external coding-agent CLI." +description: "Definition of a Coven harness and the boundary between harnesses, familiars, clients, and the daemon." +read_when: + - You are new to Coven terminology + - You need to explain why a harness is not the same thing as a familiar +--- + +# What Is a Harness? + +A harness is a coding-agent CLI that Coven can run as a supervised process. The harness is not the daemon, not a familiar, and not the user interface. It is the external agent runtime that receives a prompt and works inside a PTY. + +## Boundary map + +| Term | Role | +| --- | --- | +| Harness | External coding-agent CLI such as Codex or Claude Code. | +| Adapter | Coven's built-in mapping from harness id to executable and fixed launch arguments. | +| Daemon | Rust authority layer that validates requests, spawns PTYs, and records events. | +| Familiar | Product concept for a named agent with identity, memory, tools, and role. | +| Client | CLI, TUI, Cast Agent, OpenMeow, OpenClaw plugin, or script that asks the daemon to act. | + +## What Coven controls + +Coven controls: + +- The stable `Harness id` accepted by `coven run` and the socket API. +- The project root and working directory validation. +- The PTY process lifecycle. +- The session record and event log. +- Attach, replay, archive, summon, and destructive confirmation flow. + +## What the harness controls + +The harness controls: + +- Provider credentials and login state. +- Model selection, prompt handling, and provider API calls. +- Tool execution inside the harness process. +- Any harness-specific local cache or conversation state. + +This split keeps Coven useful without pretending to own every provider's auth model or tool runtime. + +## Current harness ids + +```bash +coven run codex "explain this repo" +coven run claude "review this module" +``` + +Use [Install harness CLIs](/docs/harnesses/installing) if either harness is missing, and [CLI run reference](/docs/cli/run) for command syntax. diff --git a/content/docs/harnesses/working-directories.mdx b/content/docs/harnesses/working-directories.mdx new file mode 100644 index 0000000..1661a8b --- /dev/null +++ b/content/docs/harnesses/working-directories.mdx @@ -0,0 +1,43 @@ +--- +title: "Working Directories" +summary: "A harness cwd must canonicalize inside the resolved project root." +description: "How Coven handles --cwd for harness sessions and why working directories cannot escape the project boundary." +read_when: + - Choosing a subdirectory for a harness run + - Debugging cwd validation failures +--- + +# Working Directories + +A working directory is the directory where the harness process starts. Coven lets you choose one with `--cwd`, but it must resolve inside the project root. + +```bash +cd /path/to/project +coven run codex "audit the API package" --cwd packages/api +``` + +## Validation rule + +The effective working directory must canonicalize inside the session's project root. + +| Input | Expected result | +| --- | --- | +| `--cwd packages/api` | Allowed when `packages/api` is inside the project root. | +| `--cwd .` | Allowed; starts from the project root/current project context. | +| `--cwd ../other-project` | Rejected if it escapes the project root. | +| Symlink escape | Rejected after canonicalization if it resolves outside the root. | + +## Why clients should still send cwd + +Good clients know the user's active pane or package folder. They should pass that as a convenience. But clients are not the trust boundary, so the daemon revalidates. + +## Troubleshooting + +If a launch fails with a cwd error: + +1. Run `pwd` and confirm you are inside the expected project. +2. Run `coven doctor` to confirm project detection. +3. Use a relative `--cwd` that exists inside the project. +4. Avoid symlinks when testing the boundary. + +See [CLI run reference](/docs/cli/run) for full command syntax. diff --git a/content/docs/meta.json b/content/docs/meta.json index dba6074..cb0cef5 100644 --- a/content/docs/meta.json +++ b/content/docs/meta.json @@ -1,3 +1,3 @@ { - "pages": ["guide", "daemon", "cli", "familiars", "reference"] + "pages": ["guide", "daemon", "cli", "harnesses", "familiars", "reference"] } diff --git a/package.json b/package.json index 89a61d8..c4b6e26 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,12 @@ "type": "module", "scripts": { "dev": "next dev", - "build": "npm run check:english-only && npm run check:daemon-docs && npm run check:cli-docs && next build", + "build": "npm run check:english-only && npm run check:daemon-docs && npm run check:cli-docs && npm run check:harness-docs && next build", "check:fumadocs": "node scripts/check-fumadocs-platform.mjs", "check:english-only": "node scripts/check-english-only.mjs", "check:daemon-docs": "node scripts/check-daemon-docs.mjs", "check:cli-docs": "node scripts/check-cli-docs.mjs", + "check:harness-docs": "node scripts/check-harness-docs.mjs", "check:links": "node scripts/validate-links.mjs", "check:mermaid": "node scripts/check-mermaid-transform.mjs && node scripts/check-mermaid-svg-normalize.mjs", "export:pdf": "node scripts/export-pdf.mjs", diff --git a/scripts/check-harness-docs.mjs b/scripts/check-harness-docs.mjs new file mode 100644 index 0000000..a3186f3 --- /dev/null +++ b/scripts/check-harness-docs.mjs @@ -0,0 +1,114 @@ +import { existsSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; + +const root = process.cwd(); +const docsRoot = join(root, 'content', 'docs'); +const harnessRoot = join(docsRoot, 'harnesses'); + +const requiredPages = [ + 'index', + 'what-is-a-harness', + 'installing', + 'provider-auth', + 'project-roots', + 'working-directories', + 'codex', + 'claude-code', + 'custom-adapters', + 'troubleshooting', +]; + +const requiredMentions = [ + 'Harness id', + 'codex', + 'claude', + 'coven run codex', + 'coven run claude', + 'coven doctor', + 'codex login', + 'claude doctor', + 'Provider credentials', + 'project root', + 'working directory', + 'PTY', + 'adapter', +]; + +function fail(message) { + console.error(`Harness docs check failed: ${message}`); + process.exit(1); +} + +function readJson(path) { + try { + return JSON.parse(readFileSync(path, 'utf8')); + } catch (error) { + fail(`could not read JSON at ${path}: ${error.message}`); + } +} + +const topLevelMeta = readJson(join(docsRoot, 'meta.json')); + +if (!Array.isArray(topLevelMeta.pages) || !topLevelMeta.pages.includes('harnesses')) { + fail('content/docs/meta.json must include a first-class "harnesses" nav section.'); +} + +const harnessMetaPath = join(harnessRoot, 'meta.json'); +if (!existsSync(harnessMetaPath)) { + fail('content/docs/harnesses/meta.json is missing.'); +} + +const harnessMeta = readJson(harnessMetaPath); + +if (harnessMeta.title !== 'Harnesses') { + fail('content/docs/harnesses/meta.json must use title "Harnesses".'); +} + +if (harnessMeta.description !== 'Deep dives for Codex, Claude Code, provider auth, project roots, working directories, and adapter boundaries.') { + fail('content/docs/harnesses/meta.json description must describe the harness deep-dive section.'); +} + +const actualPages = Array.isArray(harnessMeta.pages) ? harnessMeta.pages : []; +const missingPages = requiredPages.filter((page) => !actualPages.includes(page)); +if (missingPages.length > 0) { + fail(`content/docs/harnesses/meta.json is missing pages: ${missingPages.join(', ')}.`); +} + +const sources = []; +for (const page of requiredPages) { + const file = join(harnessRoot, `${page}.mdx`); + if (!existsSync(file)) { + fail(`missing harness doc page: content/docs/harnesses/${page}.mdx.`); + } + + const source = readFileSync(file, 'utf8'); + sources.push(source); + + if (source.includes('Stub') || source.includes('fill in')) { + fail(`content/docs/harnesses/${page}.mdx still contains stub text.`); + } + + if (!source.includes('read_when:')) { + fail(`content/docs/harnesses/${page}.mdx is missing read_when frontmatter.`); + } +} + +const joined = sources.join('\n'); +const missingMentions = requiredMentions.filter((mention) => !joined.includes(mention)); +if (missingMentions.length > 0) { + fail(`Harness docs are missing required mentions: ${missingMentions.join(', ')}.`); +} + +if (!joined.includes('/docs/cli/run') || !joined.includes('/docs/daemon/security')) { + fail('Harness docs must cross-link CLI run and daemon security docs.'); +} + +if (!readFileSync(join(harnessRoot, 'provider-auth.mdx'), 'utf8').includes('/docs/reference/auth')) { + fail('provider-auth page must link to the authentication reference.'); +} + +if (!readFileSync(join(harnessRoot, 'troubleshooting.mdx'), 'utf8').includes('/docs/cli/doctor')) { + fail('troubleshooting page must link to CLI doctor docs.'); +} + +console.log('Harness docs check passed.');