From 345f77d07da1c61248c261573e1844e981d655ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20D=C3=A9=C3=AFs=20Nuel?= Date: Sun, 12 Jul 2026 22:17:59 +0200 Subject: [PATCH] docs: tighten README prose and consolidate build instructions --- README.md | 324 ++++++++++++++---------------------------------------- 1 file changed, 85 insertions(+), 239 deletions(-) diff --git a/README.md b/README.md index 1fa5d71..df8d9b1 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,13 @@ Shenron — the configuration dragon

-Shenron keeps agent configurations aligned across AI coding assistants from -one CLI-agnostic source of truth. +Shenron keeps agent configurations aligned across AI coding assistants from one +CLI-agnostic source of truth. Define agents, prompts, slash commands, permissions, and per-agent skill bindings once in `shenron.yaml`. Shenron validates that pivot, previews the -native changes, then writes the corresponding Claude Code, Codex, and OpenCode files. +native changes, then writes the corresponding Claude Code, Codex, and OpenCode +files. ## What it supports @@ -22,8 +23,6 @@ native changes, then writes the corresponding Claude Code, Codex, and OpenCode f | Per-agent skills | YAML frontmatter `skills` | Instruction hint | Native JSON `skills` array | | Bootstrap with `shenron install` | After OpenCode | After Claude Code | Preferred import source | -Shenron targets Claude Code, Codex, and OpenCode. - ## Install Shenron requires Go 1.24 or newer. @@ -34,17 +33,13 @@ cd Shenron make build ``` -This produces `./shenron`. You can also build it directly: - -```bash -go build -o shenron ./cmd/shenron -``` +This produces `./shenron` (or run `go build -o shenron ./cmd/shenron` directly). ## Quick start -Shenron manages installed configuration packages. Every command operates on +Shenron manages installed configuration **packages**. Every command operates on a package in the store (`~/.shenron/packages/` by default); there is no -single-pivot mode. +`shenron init` or single-pivot mode. ```bash # Install a local package directory. @@ -60,7 +55,7 @@ single-pivot mode. ./shenron push my-package ``` -To work with one target only: +Work with one target only: ```bash ./shenron diff my-package --target opencode @@ -68,10 +63,10 @@ To work with one target only: ``` The first time a revision declares permission grants, `push` requires -`--allow-permissions`. After a successful push, running `diff` again -reports `No changes` for each synchronized target. +`--allow-permissions`. After a successful push, `diff` reports `No changes` for +each synchronized target. -## Commands and flags +## Commands | Command | Behavior | |---|---| @@ -81,24 +76,19 @@ reports `No changes` for each synchronized target. | `shenron diff ` | Show a package's native diff plus its permission grants and missing skills. | | `shenron push ` | Generate and atomically write a package's native files, then update its state. | -Common flags: +Flags: -- `--store ` (root, persistent) selects a custom package cache - directory (default `~/.shenron/packages`). -- `install --ref ` pins the Git revision for HTTPS sources. -- `update --source ` and `update --ref ` replace the - installed package's source and revision. -- `diff --target ` and `push --target ` select `claude-code`, - `codex`, or `opencode`. -- `push --force` overwrites native files that changed after the last push. -- `push --allow-permissions` approves the package revision's declared - permission grants; the approval is bound to the installed revision and its - permission digest. +- `--store ` (root, persistent) — custom package cache directory (default `~/.shenron/packages`). +- `install --ref ` — pin the Git revision for HTTPS sources. +- `update --source ` / `update --ref ` — replace the installed package's source and revision. +- `diff --target ` / `push --target ` — select `claude-code`, `codex`, or `opencode`. +- `push --force` — overwrite native files that changed after the last push. +- `push --allow-permissions` — approve the package revision's declared permission grants; the approval is bound to the installed revision and its permission digest. -## Pivot file +## The pivot file -The pivot is intentionally smaller than either native format. Shared concepts -stay portable; target-specific features live under `extensions`. +The pivot (`shenron.yaml`) is intentionally smaller than any native format. +Shared concepts stay portable; target-specific features live under `extensions`. ```yaml version: "1" @@ -165,81 +155,37 @@ skills: ### Agent fields -| Field | Rules and behavior | +| Field | Rules | |---|---| -| `id` | Required, unique, and matched by `^[a-z][a-z0-9-]*$`. | +| `id` | Required, unique, matched by `^[a-z][a-z0-9-]*$`. | | `description` | Required; maximum 1024 characters. | | `mode` | Required: `primary` or `subagent`. | -| `model` | Optional fallback used when the target-specific model is absent. | -| `temperature` | Optional number from `0.0` to `2.0`. | +| `model` | Optional fallback used when no target-specific model is set. | +| `temperature` | Optional, `0.0`–`2.0`. | | `systemPrompt` / `promptFile` | Mutually exclusive. `promptFile` is relative to the pivot directory and must exist. | -| `permissions` | Portable grants translated by each adapter. | -| `extensions` | Target-specific overrides and fields. | -| `skills` | Optional ordered list of kebab-case skill names, emitted as native agent metadata. Local skill existence is not required. | +| `permissions` | Portable grants (`allow`/`ask`/`deny`) translated by each adapter. | +| `extensions` | Target-specific overrides. | +| `skills` | Optional ordered list of kebab-case skill names emitted as native agent metadata. | -### Per-agent skills and global skill references +Each adapter resolves the model from `extensions..model`, then the +shared `model`, then its own default. `permissions` map to native tools per +target; see [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the per-target +translation. -These two fields have different purposes: +### Skills -- `agents[].skills` binds skills to an agent. It round-trips through OpenCode's +- `agents[].skills` binds skills to an agent and round-trips through OpenCode's JSON `skills` array and Claude Code's frontmatter `skills` list. -- Top-level `skills: [{name: ...}]` stores global references only. Shenron - does not manage skill contents or install skills on another machine. - -The repository's current dogfood bindings are documented in -[`docs/SKILLS.md`](docs/SKILLS.md). - -### Model resolution - -For agents, each adapter first looks for its target-specific override: - -1. `extensions.claude.model`, `extensions.codex.model`, or `extensions.opencode.model` -2. the shared `model` field -3. the target's own default when neither is set - -This lets one pivot select different providers or model aliases without -forcing target-specific names into the shared field. - -### Permissions - -Claude Code derives: - -- `read: allow` → `Read` -- any allowed bash rule → `Bash` -- `webfetch: allow` → `WebFetch` -- `websearch: allow` → `WebSearch` -- any allowed task → `Task` -- `edit: allow | ask | deny` → `acceptEdits | default | plan` - -`extensions.claude.tools` and `extensions.claude.permissionMode` override those -derived values. +- Top-level `skills: [{name: ...}]` stores global references only; Shenron does + not manage skill contents or install skills on another machine. -OpenCode emits `edit`, `bash`, `webfetch`, `websearch`, and `task` directly in -its `permission` object. A shared `read` value expands to `glob`, `grep`, -`list`, and `lsp`; `extensions.opencode.permission` can override those four -sub-permissions individually. - -Codex derives a coarse sandbox from `edit`, and maps `websearch` to Codex's -native search mode. Command-pattern bash rules, `read`, `webfetch`, and task -permissions have no equivalent per-agent Codex enforcement. Use -`extensions.codex` (`sandboxMode`, `approvalPolicy`, and `webSearch`) for an -explicit native override. Codex receives each agent skill list as an -instruction hint; Shenron does not resolve local skill paths or install skills. - -## Getting started - -Shenron ships its configuration as a directory containing a manifest and a -pivot. Hand-write one or import the first usable native config you already -have, then install it with `shenron install`. There is no `shenron init` — -every command operates on an installed package. +The repository's current dogfood bindings are in [`docs/SKILLS.md`](docs/SKILLS.md). ## Configuration packages -A package bundles a pivot together with a manifest and ships as a -self-contained directory. Use packages when the same configuration should be -reliably installed on many machines or released to other users. - -A package directory looks like this: +A package bundles a pivot with a manifest and ships as a self-contained +directory, so the same configuration can be installed on many machines or +released to other users. ```text my-package/ @@ -247,12 +193,9 @@ my-package/ └── shenron.yaml # pivot: agents, commands, permissions ``` -`shenron-package.yaml` validates `schemaVersion: "1"`, a kebab-case `name` -matching `^[a-z][a-z0-9-]*$`, a strict semver `version`, a non-empty -`description`, and the `skills.required` / `skills.optional` arrays. Every -`promptFile` referenced by the pivot must stay inside the package directory. - -### Install a package +The manifest validates `schemaVersion: "1"`, a kebab-case `name`, a strict +semver `version`, a non-empty `description`, and `skills.required` / +`skills.optional`. Every `promptFile` must stay inside the package directory. ```bash # Local directory @@ -260,138 +203,50 @@ matching `^[a-z][a-z0-9-]*$`, a strict semver `version`, a non-empty # Public Git repository (HTTPS only, immutable tag or full commit SHA) ./shenron install https://github.com/acme/reviewers.git --ref 1.2.0 -``` - -The first install copies the source into a content-addressed snapshot under -`~/.shenron/packages///`. Each subsequent `install` from Git -requires `--ref`; branches and `HEAD` are refused. The snapshot's digest is -revalidated before every load, so a corrupted cache can never be pushed. - -### List and update - -```bash -./shenron list # name, version, source, revision -./shenron update acme-reviewers \ - --source https://github.com/acme/reviewers.git --ref 1.3.0 -``` - -`update` stages and validates the new snapshot before swapping the active -record. Old snapshots are retained. -### Diff and push - -```bash -./shenron diff acme-reviewers # preview without writing -./shenron push acme-reviewers --allow-permissions +# Update to a new source or ref +./shenron update acme-reviewers --source https://github.com/acme/reviewers.git --ref 1.3.0 ``` -`diff` reports the same created / modified / manually-modified / orphaned -status the package flow has always reported, and additionally surfaces the -package's declared permission grants plus any required or optional skills -missing on disk. - -`push` requires explicit approval the first time a revision declares -permission grants. The approval is bound to both the package revision and the -SHA-256 digest of the normalized grant list (`state//permissions.json`), -so a new revision with changed grants must be approved again. Missing required -skills abort the push; missing optional skills emit a warning and continue. - -Packages also refuse to take over native resources they do not already own. -If a generated path (or a managed nested entry inside `opencode.json`) exists -on disk without being tracked in the package's own state file, `push` returns -`ErrPackageCollision` and aborts. `push --force` overwrites manually edited -package-owned files. - -State for a package lives at `~/.shenron/state//.shenron-state.json`, -kept outside the immutable snapshot so it survives revisions. - -## Synchronization and safety - -The sync pipeline is: - -1. Discover, parse, and validate the pivot. -2. Generate each target's files in memory. -3. Merge OpenCode agent and command fragments into the existing JSON. -4. Compare generated content with disk and `.shenron-state.json`. -5. Write changed files atomically and record their hashes. - -### OpenCode merge policy - -Shenron upserts pivot agents and commands into the nested `agent` and -`command` objects. Native-only entries and unrelated top-level fields are -preserved, and existing key order is retained where possible. The JSON document -is parsed and serialized again, so byte-for-byte formatting is not guaranteed. - -The merge is deliberately upsert-only. Removing an agent or command from the -pivot does not delete its nested OpenCode entry; remove stale JSON entries by -hand. Standalone managed files that are no longer generated can be reported as -orphaned, but Shenron still leaves deletion to you. - -### Manual-edit protection - -`.shenron-state.json`, stored beside the pivot, records the hash of every file -written by a successful push. If a managed native file later differs from both -that state and the newly generated output, Shenron marks it as manually -modified and refuses to overwrite it. Review the diff, reconcile the change, or -use `push --force` deliberately. +Each install copies the source into a content-addressed snapshot under the +store. Git sources require `--ref` (an immutable tag or full commit SHA); +branches, `HEAD`, SSH, and archive URLs are refused. The snapshot digest is +revalidated before every load, so a corrupted cache can never be pushed. Old +snapshots are retained across updates. + +## Safety + +- **Manual-edit protection** — `.shenron-state.json` records the hash of every + file written by a successful push. If a managed native file later differs from + both that state and the newly generated output, `push` refuses to overwrite it. + Review the diff, reconcile, or use `push --force` deliberately. +- **Permission approval** — the first push of a revision that declares + permission grants requires `--allow-permissions`. The approval is bound to the + revision and the SHA-256 digest of the normalized grant list, so changed grants + must be approved again. Missing required skills abort the push; missing + optional skills warn and continue. +- **Foreign collisions** — `push` refuses to take over native resources it does + not already own, returning `ErrPackageCollision`. `push --force` overwrites + manually edited package-owned files. +- **OpenCode merge** — Shenron upserts pivot agents and commands into + `opencode.json` and preserves native-only entries and unrelated top-level + fields. The merge is upsert-only; removing an item from the pivot does not + delete its nested entry. + +See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the full synchronization +pipeline and adapter internals. ## Current limitations -- Sync is pivot-to-native; there is no automatic native-to-pivot merge after - initialization. -- Native entries removed from the pivot are warned about, not deleted. +- Sync is pivot-to-native only; there is no automatic native-to-pivot merge. +- Native entries removed from the pivot are reported, not deleted. - Skill bindings are metadata only; skill directories and `SKILL.md` contents - are outside Shenron's management scope. -- Skill-name validation checks kebab-case syntax, not local filesystem - availability. + are outside Shenron's scope. - OpenCode JSON is structurally preserved, not guaranteed byte-identical. -- Package installs accept only local directories or public HTTPS Git - repositories, and HTTPS sources require an immutable tag or full commit - SHA. Branches, `HEAD`, SSH, and archive URLs are refused. +- Git installs accept only public HTTPS repositories with an immutable tag or + full commit SHA. -## Architecture for contributors - -```text -cmd/shenron/ Cobra entry point -internal/ - cli/ install, list, update, diff, push commands, registry, orchestration - pivot/ YAML schema, discovery, parsing, validation - package/ shenron-package.yaml manifest, immutable snapshots, Git and local install - adapter/ - claude/ Markdown/frontmatter and command-file generation - codex/ TOML custom-agent and Markdown custom-prompt generation - opencode/ JSON fragments, ordered merge, prompt/command files - diff/ status calculation, unified diffs, state hashes - fsutil/ target paths and atomic file replacement -testdata/ end-to-end fixtures -docs/ PRD, plans, and skill-binding matrix -``` - -The core consumes the `adapter.Adapter` interface: - -```go -type Adapter interface { - Name() string - ValidateAgent(pivot.AgentDefinition) error - GenerateAgent(pivot.AgentDefinition) (map[string]string, error) - GenerateCommand(pivot.CommandDefinition) (map[string]string, error) - TargetPaths() []string - MergeFile(path string, existing []byte, fragments map[string]any) ([]byte, error) -} -``` - -OpenCode additionally exposes an internal fragment accumulator so orchestration -can merge all generated agent and command fragments into one `opencode.json`. -Claude Code generates independent files and returns no merged file. - -To add a target: - -1. Implement the adapter interface in `internal/adapter/`. -2. Keep target-specific translation inside that package. -3. Register the adapter in `internal/cli/registry.go`. -4. Add mapping tests, golden fixtures, and end-to-end coverage. - -## Testing and development +## Development ```bash make test # go test ./... @@ -400,21 +255,12 @@ make build # go build -o shenron ./cmd/shenron make clean # remove the local binary ``` -The test suite contains: - -- pivot parsing, validation, and discovery tests; -- adapter mapping and golden-file tests; -- ordered OpenCode merge and preservation tests; -- CLI bootstrap, diff, push, force, and orphan-scope tests; -- cobra-driven surface tests for the five top-level commands - (`commands_test.go`); -- install, list, update, diff, push, permissions, skills, and - foreign-collision tests against the package store; -- atomic-write and state-file tests; -- end-to-end round-trip tests for all three targets, including per-agent skills. - -The root `shenron.yaml`, generated `shenron` binary, and +The root `shenron.yaml`, the generated `shenron` binary, and `.shenron-state.json` are local dogfood artifacts and are gitignored. -For the detailed product contract, see -[`docs/prd/shenron.md`](docs/prd/shenron.md). +## Further reading + +- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — module map, sync pipeline, + adapter internals, and the extension guide for adding new targets. +- [`docs/prd/shenron.md`](docs/prd/shenron.md) — the detailed product contract. +- [`docs/SKILLS.md`](docs/SKILLS.md) — current dogfood skill bindings.