cc-guides

module
v0.1.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2026 License: MIT

README

cc-guides

Write the prose you own; import the guides you share. cc-guides composes AGENTS.md, CLAUDE.md, and shell scripts from local fragments and shared guides pulled in by reference, and cc-guides check fails CI the moment an artifact drifts.

Release CI

Get started

brew install yasyf/tap/cc-guides

A repo describes each generated file with a .claude/fragments/<target>/ directory: a layout.toml that composes local *.fragment.* prose with imports of shared guides, plus the local pieces. Each imported alias names its source in a [sources.<alias>] table. render fetches each import at a pinned commit, writes the target with a version-free GENERATED marker, and records every pin in a lock file:

$ cat .claude/fragments/AGENTS.md/intro.fragment.md
# Acme

House rules for agents.

$ cat .claude/fragments/AGENTS.md/layout.toml
fragments = [
  "intro",
  "cc-skills:ccx",
]

[sources.cc-skills]
source = "github:yasyf/cc-skills@main"

$ cc-guides render
rendered .claude/fragments/AGENTS.md -> AGENTS.md

$ head -6 AGENTS.md
<!-- GENERATED by cc-guides from .claude/fragments/AGENTS.md/ — do not edit; edit the fragments and run 'cc-guides render'. -->
# Acme

House rules for agents.

## Compact Context (ccx)

intro is your prose; cc-skills:ccx arrives verbatim from the shared guides in cc-skills, identical across every repo that imports it. Change the shared guide once and every repo re-renders. render also writes .claude/fragments/cc-guides.lock, which pins every source to the exact commit the artifacts were built against; check and the CI action read it, so a new cc-guides release never reddens a repo that has not re-rendered.

Driving with an agent? Paste this:

Install cc-guides (`brew install yasyf/tap/cc-guides`). I have a hand-written
AGENTS.md — migrate it: run `cc-guides init AGENTS.md`, commit the
.claude/fragments/AGENTS.md/ directory it produces, and wire `cc-guides check`
into CI. Reference: `cc-guides --help`.

Use cases

Fail CI when an artifact drifts

An artifact edited by hand, or left stale after a shared guide changed, should redden the build. check re-composes each target in memory — pinned to the commits the lock records — and byte-compares against disk:

$ cc-guides check
OK	AGENTS.md

$ echo "agent slop" >> AGENTS.md
$ cc-guides check
STALE	AGENTS.md
$ echo "exit: $?"
exit: 1

OK, STALE, and MISSING go to stdout as TSV; exit 1 signals drift, 2 an invalid layout. In GitHub Actions, one step gates every artifact:

- uses: actions/checkout@v7
- uses: yasyf/cc-guides@action-v1

The action installs the exact cc-guides version the lock records, so a new release never reddens a repo that has not re-rendered yet.

Keep one repo's spin on a shared guide

A repo needs its own version of a guide the rest of the fleet shares. Compose a local fragment in the slot where the import would sit — no import, no shadowing:

fragments = [
  "intro",
  "ccx",          # local ccx.fragment.md, not cc-skills:ccx
]

render reads ccx.fragment.md from the artifact dir instead of fetching the shared guide, and a layout that imports nothing locks no sources at all.

Migrate an existing repo

A repo already rendered by an older cc-guides, or holding a hand-pasted guide, moves to the layout shape in one command. migrate converts a v1 X.src.md source; init converts a hand-written stamped artifact. Both write the .claude/fragments/<target>/ directory and self-verify the composition reproduces the current artifact byte-for-byte, refusing to write on a mismatch:

$ cc-guides migrate AGENTS.src.md
MIGRATED	AGENTS.src.md -> .claude/fragments/AGENTS.md/

Composition

An artifact dir is any directory under .claude/fragments/ that holds a layout.toml, and its path below that root is the target it renders. .claude/fragments/AGENTS.md/ renders AGENTS.md; a nested path renders a nested target. The kind — Markdown, shell comment style, or JSON — comes from the target extension. A JSON target deep-merges its pieces (arrays concatenate, objects merge) and carries no marker; the lock is its only drift record.

layout.toml is an ordered, heterogeneous fragments array. The array comes first, before any [sources.*] table: a top-level key written after a table header nests inside that table, and the binary hard-errors on that shape instead of composing empty.

fragments = [
  "agents-md",                       # local: agents-md.fragment.md in this dir
  "cc-skills:ccx",                   # import: the ccx guide from cc-skills
  { use = "cc-skills:install-binary-latest", args = { binary = "slop-cop", plugin = "slop-cop", repo = "yasyf/slop-cop", brew = "yasyf/tap/slop-cop" } },
]

[sources.cc-skills]                  # required: every imported alias declares its source
source = "github:yasyf/cc-skills@main"

A string entry is a local <name>.fragment.<ext> or an alias:name import; an inline table adds args that fill {{token}} placeholders in the imported body. Every imported alias needs its own [sources.<alias>] table — there is no baked-in default. A source spec takes one of two forms: the manifest form github:<owner>/<repo>[@<ref>], which follows the target repo's cc-guides.toml to its guides dir, or the explicit-path form github:<owner>/<repo>//<path>[@<ref>], which points straight at a subtree. Pieces join with one blank line between them, LF only, one trailing newline. Prose is never token-substituted, so ${{ github.sha }} and {{VAR}} survive verbatim.

Commands

One invocation per surface; run cc-guides <command> --help for the full flag list.

Command What it does
render [paths…] Compose each artifact dir to its target. No paths: discover every layout under the repo.
check [paths…] Re-compose in memory, pinned to the lock's commits, and byte-compare. TSV OK/STALE/MISSING; exit 1 on drift, 2 on invalid input.
migrate [paths…] Convert a v1 X.src.{md,sh} source to an artifact dir, self-verifying the round-trip.
init <artifact> Convert a hand-written stamped markdown artifact to an artifact dir.
lint <dir> Check a shared-guides directory for purity: LF, one trailing newline, kind, shell shebang.
list List each artifact dir and the fragments it composes.
cat <ref> Print a fragment body: an alias:name import or a local piece by name.

--source alias=<spec> overrides where an import resolves — a github: spec or a local directory for development. --version prints the cc-guides version, which render stamps into the lock.

How it fits together

cc-guides ships two things: this binary and an importable GitHub Action. The content lives in its consumers — cc-skills is the reference home for the shared guides, and each repo carries its own layouts. An import resolves to an immutable commit through git ls-remote, fetches that tree from codeload, and caches it under the user cache dir; every artifact in a run pins the same sha, recorded in .claude/fragments/cc-guides.lock. check reads those pins from the lock, so it reproduces an artifact offline once the cache is warm and never false-fails across binary versions. Build, test, and lint conventions live in AGENTS.md.

task test   # go test -race ./...
task ci     # vet, lint, test, build

Licensed under MIT.

Directories

Path Synopsis
cmd
cc-guides command
Command cc-guides: Canonical agent guides as a shipped Go binary — render AGENTS.md, CLAUDE.md, and shell artifacts from embedded, versioned fragments
Command cc-guides: Canonical agent guides as a shipped Go binary — render AGENTS.md, CLAUDE.md, and shell artifacts from embedded, versioned fragments
Package guide is a generic, kind-aware renderer for source files that expand column-0 `{{> name}}` include directives against a Resolver and carry a stable GENERATED banner.
Package guide is a generic, kind-aware renderer for source files that expand column-0 `{{> name}}` include directives against a Resolver and carry a stable GENERATED banner.
internal
cli
Package cli builds the cobra command tree and owns exit-code mapping.
Package cli builds the cobra command tree and owns exit-code mapping.
legacy
Package legacy is init's first stage: it collapses stamped canonical blocks in a handwritten markdown artifact into `{{> name}}` directives and self-verifies the synthesized v1 source re-renders to the original.
Package legacy is init's first stage: it collapses stamped canonical blocks in a handwritten markdown artifact into `{{> name}}` directives and self-verifies the synthesized v1 source re-renders to the original.
log
Package log configures the process-wide structured logger.
Package log configures the process-wide structured logger.
migrate
Package migrate converts a v1 source (root X.src.md with {{> name}} directives) into the v3 shape: a .claude/fragments/<target>/ artifact dir holding repo-local `*.fragment.*` prose pieces and a layout.toml that composes them alongside imports of shared fragments.
Package migrate converts a v1 source (root X.src.md with {{> name}} directives) into the v3 shape: a .claude/fragments/<target>/ artifact dir holding repo-local `*.fragment.*` prose pieces and a layout.toml that composes them alongside imports of shared fragments.
version
Package version exposes the build version.
Package version exposes the build version.
Package layout parses and validates a `.claude/fragments/<target>/layout.toml` file — the per-repo config surface that composes an ordered list of local fragments and imports of shared fragments from another repo.
Package layout parses and validates a `.claude/fragments/<target>/layout.toml` file — the per-repo config surface that composes an ordered list of local fragments and imports of shared fragments from another repo.
Package lockfile reads and writes .claude/fragments/cc-guides.lock — the repo-level provenance record that moves version and commit pins out of artifact banners.
Package lockfile reads and writes .claude/fragments/cc-guides.lock — the repo-level provenance record that moves version and commit pins out of artifact banners.
Package source resolves shared-fragment imports: it parses a `github:<owner>/<repo>//<path>[@<ref>]` spec, resolves a ref to an immutable commit sha (shelling out to `git ls-remote`), fetches that commit's tree as a codeload tarball, and caches the extracted subpath under the user cache dir.
Package source resolves shared-fragment imports: it parses a `github:<owner>/<repo>//<path>[@<ref>]` spec, resolves a ref to an immutable commit sha (shelling out to `git ls-remote`), fetches that commit's tree as a codeload tarball, and caches the extracted subpath under the user cache dir.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL