Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions .github/workflows/parity-watch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ env:
UPSTREAM: langchain-ai/openwiki
# Keep this in sync with "Upstream validated against" in PARITY.md.
PINNED_SHA: 23428de0cc0b1b6d3e5d09be413e92a5d6ee451f
# The files whose change means the spec changed. Ports of these drive parity:
# test/update-noop.test.ts -> tests/noop.test.ts
# src/agent/utils.ts -> scripts/check-noop.sh
# src/agent/prompt.ts -> references/disciplines.md, agents/wiki-scout.md
SPEC_FILES: "test/update-noop.test.ts src/agent/utils.ts src/agent/prompt.ts"
# The spec-bearing files wijzer vendors at the pinned SHA into vendor/openwiki/.
# A change to any of them means the spec moved; each is verified against real
# vendored code, not a hand-port:
# test/update-noop.test.ts -> run verbatim from vendor/ + tests/parity-crossvalidate.test.ts
# src/agent/utils.ts -> scripts/check-noop.sh + snapshot.sh (cross-validated vs the real functions)
# src/agent/prompt.ts -> references/disciplines.md + wiki-format.md (generated) + agents/wiki-scout.md
# src/constants.ts -> OPEN_WIKI_DIR / UPDATE_METADATA_PATH used across scripts + generator
# src/agent/types.ts -> references/state-schema.md field set (locked to UpdateMetadata)
SPEC_FILES: "test/update-noop.test.ts src/agent/utils.ts src/agent/prompt.ts src/constants.ts src/agent/types.ts"
# The reference wiki folder that defines the output format.
REFERENCE_DIR: "openwiki"
ISSUE_TITLE: "parity-watch: upstream OpenWiki spec changed"
Expand Down Expand Up @@ -91,7 +95,9 @@ jobs:
echo "### Next steps"
echo ""
echo "Run the re-validation procedure in [PARITY.md](../blob/main/PARITY.md):"
echo "port any changed no-op cases, re-diff the wiki format if it moved,"
echo "re-vendor at the new SHA (\`scripts/vendor-openwiki.sh --sha <new>\`),"
echo "re-derive the generated docs (\`node scripts/build-disciplines.mjs\`),"
echo "run \`npm test\` (the vendored \`update-noop.test.ts\` + cross-validation re-prove parity),"
echo "then bump the pin (this file's \`PINNED_SHA\` and PARITY.md) and note it in CHANGELOG.md."
echo "PARITY_EOF"
} >> "$GITHUB_OUTPUT"
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,17 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
literals are exempt from vocabulary translation and the residual-vocab guard).
This reverses P2C's inject-pointer.sh adaptation.
- `agents/wiki-scout.md` is aligned to the generated subagent discipline.
- **P2E — parity reconciliation.** Squared the docs and tests with the vendored-
real-code reality: `PARITY.md`'s verification column now cites the actual
verifiers (`tests/parity-crossvalidate.test.ts`, the verbatim vendored
`update-noop.test.ts`, `tests/build-disciplines.test.ts` drift-lock,
`tests/check-format.test.ts`) instead of aspirational "Phase N" runs.
`.github/workflows/parity-watch.yml` now watches the full vendored spec set
(adds `src/constants.ts` + `src/agent/types.ts`), drops the stale
`tests/noop.test.ts` mapping, and drives the re-vendor → regenerate → `npm test`
flow on a SHA bump. Trimmed the two parity-*restatement* assertions from
`tests/plugin-structure.test.ts` (per the parity-first principle: the ≤8-page
and <5-files→1–2-pages numbers are pinned in `tests/build-disciplines.test.ts`
against drift-locked docs, and `## Source map` / `Git evidence:` are enforced in
`tests/check-format.test.ts`). `README.md` now states Node is a dev/CI-only
dependency — the plugin needs no `node` at user runtime.
11 changes: 11 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,14 @@ state file stays `openwiki/.last-update.json` with the exact
split (`shasum` vs `sha256sum`) is bridged in `scripts/lib/json.sh`.
- When OpenWiki drifts, follow the re-validation procedure in PARITY.md and bump
the pinned SHA — never silently claim parity.

## OpenWiki

This repository has documentation located in the /openwiki directory.

Start here:
- [OpenWiki quickstart](openwiki/quickstart.md)

OpenWiki includes repository overview, architecture notes, workflows, domain concepts, operations, integrations, testing guidance, and source maps.

When working in this repository, read the OpenWiki quickstart first, then follow its links to the relevant architecture, workflow, domain, operation, and testing notes.
14 changes: 7 additions & 7 deletions PARITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ living record of what that means and how it is verified.

| OpenWiki behavior (upstream) | wijzer mechanism | Verified by |
|---|---|---|
| `openwiki --init [msg]` | `/wijzer:init [msg]` skill | golden run (Phase 2) vs their committed `openwiki/` |
| `openwiki --update [msg]` | `/wijzer:update [msg]` skill | `tests/parity-crossvalidate.test.ts` + Phase-3 scenarios |
| chat mode (Q&A, no writes) | `/wijzer:ask` skill | manual: assert zero wiki writes |
| `--print` non-interactive | `claude -p "/wijzer:update"` | headless recipe (Phase 4) |
| plain-MD pages, no frontmatter, source-map at page end, ≤8 pages on init | `references/wiki-format.md` + `scripts/check-format.sh` gate in init/update | `tests/check-format.test.ts` + golden run vs upstream `openwiki/` |
| `openwiki --init [msg]` | `/wijzer:init [msg]` skill | golden `/wijzer:init` run + `scripts/check-format.sh` gate (`tests/check-format.test.ts`) |
| `openwiki --update [msg]` | `/wijzer:update [msg]` skill | `tests/parity-crossvalidate.test.ts` (no-op/snapshot vs the real functions) + golden update run |
| chat mode (Q&A, no writes) | `/wijzer:ask` skill | `tests/plugin-structure.test.ts` (ask is structurally read-only) |
| `--print` non-interactive | `claude -p "/wijzer:update"` | `examples/headless.md` recipe |
| plain-MD pages, no frontmatter, source-map at page end, ≤8 pages on init | `references/wiki-format.md` + `scripts/check-format.sh` gate in init/update | `tests/check-format.test.ts` (format-gate enforcement) + golden-run conformance |
| `.last-update.json` = {updatedAt, command, gitHead?, model} | `scripts/write-state.sh` | `tests/state.test.ts` (CLI contract) + `tests/parity-crossvalidate.test.ts` (real-function interchange) |
| no-op: (no msg AND HEAD==state) OR only `openwiki/` changed; force when dirty | `scripts/check-noop.sh` (ports `getUpdateNoopStatus` + `shouldCheckUpdateNoop`) | `tests/parity-crossvalidate.test.ts` runs bash vs the vendored real functions; `vendor/openwiki/test/update-noop.test.ts` runs verbatim against the vendored source |
| git evidence (`git status`/`log <range>`/`diff`) → surgical edits: ≤1–2 pages when <5 files changed | `references/disciplines.md` (git discipline) — **prompt-driven**: the update skill runs the same commands and the same `gitHead` → `updatedAt` → recent-history fallback as OpenWiki's `createGitSummary`, reading the baseline from `openwiki/.last-update.json` | Phase-3 scenario |
| git evidence (`git status`/`log <range>`/`diff`) → surgical edits: ≤1–2 pages when <5 files changed | `references/disciplines.md` (git discipline) — **prompt-driven**: the update skill runs the same commands and the same `gitHead` → `updatedAt` → recent-history fallback as OpenWiki's `createGitSummary`, reading the baseline from `openwiki/.last-update.json` | git discipline drift-locked in `tests/build-disciplines.test.ts`; commands mirror `createGitSummary` (`vendor/openwiki/src/agent/utils.ts`) |
| SHA-256 snapshot; write state only if content changed | `scripts/snapshot.sh` (`dir:`/`file:` frames match real byte-for-byte) + update-skill gate | `tests/snapshot.test.ts` (envelope) + `tests/parity-crossvalidate.test.ts` (digest equals real) |
| init: discover → `_plan.md` → generate → delete plan → state | **prompt-driven** discovery (run discipline) + init skill; no bash inventory step (OpenWiki has none) | golden run |
| run/subagent/planning/git disciplines (`src/agent/prompt.ts`) | `references/disciplines.md` + `references/wiki-format.md` (both **generated** from the vendored `prompt.ts` by `scripts/build-disciplines.mjs`) + `agents/wiki-scout.md` | `tests/build-disciplines.test.ts` — drift-locked: the committed docs must equal a fresh regenerate, so an upstream prompt change fails CI until re-derived |
| exact `## OpenWiki` block in AGENTS.md/CLAUDE.md | **prompt-driven**: the agent writes OpenWiki's verbatim `## OpenWiki` section (preserved byte-for-byte in `references/disciplines.md`) — no bash injector | `tests/build-disciplines.test.ts` (block derived verbatim) |
| GH Action: cron 8am → update → PR `openwiki/update` | `examples/github-action.yml` (via anthropics/claude-code-action, subscription OAuth) | Phase-4 live run |
| GH Action: cron 8am → update → PR `openwiki/update` | `examples/github-action.yml` (via anthropics/claude-code-action, subscription OAuth) | manual live run |

## Watch items

Expand Down
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,30 @@ verified, and [`CONTRIBUTING`](#contributing) below to hack on it.

- Claude Code with an active Claude subscription.
- `git` and a POSIX shell. On Windows, use Git Bash or WSL.
- **No Node.js at runtime.** The plugin is skills + dependency-free bash; nothing
it runs for you needs `node`. Node is a **development/CI-only** dependency —
it's used to run the Vitest suite and to regenerate `references/disciplines.md`
and `references/wiki-format.md` from the vendored OpenWiki prompt (the committed
output ships in the plugin, so you never run the generator).

## Contributing

Node is needed here (dev/CI only), not by end users:

```
npm install
npm test # runs the deterministic script suite against temp git repos
npm test # Vitest: scripts vs temp git repos + the vendored OpenWiki parity tests
npm run lint # shellcheck
```

When OpenWiki evolves, re-derive the generated doctrine and re-prove parity:

```
scripts/vendor-openwiki.sh --sha <new> # re-vendor the spec at a new SHA
node scripts/build-disciplines.mjs # regenerate the reference docs
npm test # cross-validation re-proves parity
```

Contributions welcome — especially parity fixes when OpenWiki evolves (see the
re-validation procedure in [PARITY.md](PARITY.md)).

Expand Down
6 changes: 6 additions & 0 deletions openwiki/.last-update.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"updatedAt": "2026-07-08T16:28:46Z",
"command": "init",
"gitHead": "1510ee58ab76769a1f0091b7cd78347b64625d54",
"model": "claude-opus-4-8"
}
72 changes: 72 additions & 0 deletions openwiki/architecture/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Architecture overview

wijzer separates **deterministic bookkeeping** from **model judgment**. Anything
with exact semantics that must match OpenWiki byte-for-byte is a dependency-free
bash script; anything requiring understanding of a codebase is prompt-driven and
done by the model. This page maps the directories and the scripts.

## The split

- **`scripts/`** — dependency-free bash (git + coreutils). Each script owns one
piece of exact-semantics bookkeeping and prints a single JSON object on stdout
(exit 0 = ran, 2 = precondition missing, e.g. not a git repo).
- **`skills/` + `agents/`** — model judgment. The skills drive discovery, git
inspection, page authoring, and the pointer block; they *call* the scripts for
bookkeeping but never re-implement it.
- **`references/`** — the doctrine the skills obey. `disciplines.md` and
`wiki-format.md` are **generated** from the vendored OpenWiki prompt (see
[Parity](../parity/overview.md)); `state-schema.md` is hand-written.
- **`vendor/openwiki/`** — the pinned upstream OpenWiki source used as the parity
oracle (executed directly by the tests).

## The bookkeeping scripts

Four scripts carry exact OpenWiki semantics and are cross-validated against the
vendored real functions:

- **`check-noop.sh`** — decides whether a `/wijzer:update` run is a no-op (ports
OpenWiki's `getUpdateNoopStatus` + `shouldCheckUpdateNoop`). Emits `noop`,
`reason`, `gitHead`, `stateGitHead`, `dirty`, `commitsSince`. A non-empty user
message short-circuits to force a run.
- **`snapshot.sh`** — a SHA-256 content snapshot of `openwiki/` (excluding the
state file), so the update skill can tell whether its edits changed anything
and skip churn. Mirrors `createOpenWikiContentSnapshot` byte-for-byte.
- **`write-state.sh`** — writes `openwiki/.last-update.json` (`{updatedAt,
command, gitHead?, model}`), the interchangeable run-metadata file. Validates
the model id and falls back to the `claude-code` literal.
- **`check-format.sh`** — the format-parity gate: verifies a generated wiki obeys
`references/wiki-format.md` (no YAML frontmatter, `## Source map` shape, the
`Git evidence:` bullet, quickstart linking headings) before state is recorded.

`scripts/lib/json.sh` provides shared JSON-string escaping and bridges the
macOS/Linux `shasum` vs `sha256sum` split. `scripts/vendor-openwiki.sh` re-vendors
the upstream source at a pinned SHA; `scripts/build-disciplines.mjs` is the
dev/CI-only doc generator (the one exception to the dependency-free-bash rule).

## Conventions

- Bash: `set -euo pipefail`; guard `grep` pipelines that may legitimately match
nothing with `|| true`; prefer `awk 'NR<=n'` over `head -n` inside pipelines to
avoid SIGPIPE aborts. Keep scripts portable (macOS bash 3.2 + GNU).
- Every `scripts/<name>.sh` has a co-located `tests/<name>.test.ts` exercising it
against a real temp git repo (behavioral, not implementation).

## Tests

The suite (Vitest) runs the scripts against real temporary git repos and runs the
vendored OpenWiki code directly as the parity oracle. Notable files:
`tests/parity-crossvalidate.test.ts` (bash vs the real functions),
`tests/vendor-openwiki.test.ts` (vendor drift-lock + the verbatim upstream
`update-noop.test.ts`), `tests/build-disciplines.test.ts` (generated-doc
drift-lock + guard error paths), and `tests/check-format.test.ts`,
`tests/snapshot.test.ts`, `tests/state.test.ts`, `tests/plugin-structure.test.ts`.

## Source map

- `scripts/check-noop.sh`
- `scripts/snapshot.sh`
- `scripts/write-state.sh`
- `scripts/check-format.sh`
- `scripts/lib/json.sh`
- `CLAUDE.md`
- Git evidence: commits `8536c2a`, `511f237`
64 changes: 64 additions & 0 deletions openwiki/parity/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Parity model

wijzer's whole reason to exist is running OpenWiki's documentation behavior on a
Claude subscription instead of a metered API. That only matters if the output is
**interchangeable** with OpenWiki's. This page explains how wijzer achieves parity
and, crucially, how it *proves* parity against real upstream code rather than
assuming it. The living contract is [PARITY.md](../../PARITY.md).

## What parity covers

Interchangeable: the `openwiki/` layout and Markdown page format, the
`openwiki/.last-update.json` state schema, the update no-op / churn-prevention
algorithm, and the AGENTS.md/CLAUDE.md pointer block. Out of scope: OpenWiki's
provider/credential machinery (wijzer's runtime is Claude Code), its CLI flag
surface, and byte-identical page prose.

## Vendored source as the oracle

wijzer cannot run the OpenWiki *agent* (that needs an API key — the whole reason
wijzer exists). It doesn't need to: OpenWiki's deterministic bookkeeping is pure
git + filesystem logic with no LLM in the loop. `scripts/vendor-openwiki.sh`
freezes that source at a pinned SHA into `vendor/openwiki/` (with a blob-SHA
manifest and `PROVENANCE.md`), and the tests **execute it directly**:

- `tests/parity-crossvalidate.test.ts` runs wijzer's bash and the vendored real
functions over the same temp repos and asserts they agree.
- `vendor/openwiki/test/update-noop.test.ts` runs **verbatim** against the
vendored source — the upstream spec test is the parity spec, no hand-porting.
- `tests/vendor-openwiki.test.ts` locks every vendored file to its manifest blob
SHA, so any drift is loud.

## Generated doctrine

The run / subagent / planning / git disciplines and the wiki output format are
not hand-written — they are **derived from the vendored prompt**.
`scripts/build-disciplines.mjs` (dev/CI-only Node) text-parses
`vendor/openwiki/src/agent/prompt.ts`, applies a documented tool-vocabulary
translation (OpenWiki's DeepAgents virtual filesystem → Claude Code
`Read`/`Grep`/`Glob`/`Write`/`Edit`/`Bash`, the `task` tool → `Task` +
`wiki-scout`), and writes `references/disciplines.md` + `references/wiki-format.md`.
The exact `## OpenWiki` pointer block is preserved verbatim (fenced blocks are
exempt from translation). `tests/build-disciplines.test.ts` drift-locks the
committed docs to a fresh regenerate, so an upstream prompt change fails CI until
a human re-derives and reviews.

## Watching upstream + re-validation

`.github/workflows/parity-watch.yml` compares the vendored spec files against
upstream `main` weekly and opens a tracking issue on drift. The response is the
re-validation procedure in [PARITY.md](../../PARITY.md): re-vendor at the new SHA,
regenerate the docs, run `npm test` (cross-validation re-proves parity), then bump
the pin and note it in the changelog. wijzer never claims parity it hasn't
re-proven.

## Source map

- `PARITY.md`
- `scripts/vendor-openwiki.sh`
- `scripts/build-disciplines.mjs`
- `vendor/openwiki/PROVENANCE.md`
- `tests/parity-crossvalidate.test.ts`
- `tests/vendor-openwiki.test.ts`
- `.github/workflows/parity-watch.yml`
- Git evidence: commits `f1cc4ff`, `2ff0c3a`, `f34a82d`
Loading
Loading