diff --git a/.github/docs-corpus/check_corpus_currency.sh b/.github/docs-corpus/check_corpus_currency.sh deleted file mode 100644 index 343e8360..00000000 --- a/.github/docs-corpus/check_corpus_currency.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env bash -# check_corpus_currency.sh — REPORT the pinned corpus's currency. It never fails. -# -# The corpus pin is advanced by a MANUAL act after the corpus lands, so the site -# trails the corpus by however long nobody ran the regeneration — and the drift -# gate CANNOT see it: the PINNED corpus regenerates its own (old) pages -# perfectly, so a stale corpus is invisible to it. The drift gate answers "does -# the committed content match what the pinned inputs generate?" (yes, always); -# this answers the second question — "is the pinned corpus itself current?". -# -# The answer is REPORTED, never failed. A corpus that is behind is an advance -# available NOW — the same shape the pin contract calls `behind`: a reportable -# state, not a broken edge. A gate that FAILED on it would be red on every push -# until somebody ran the regeneration PR, and the remedy is that PR, not a gate. -# -# THE STATES ARE THE PIN CONTRACT'S (umbrella AGENTS.md Part II rule 3): `cur`, -# `behind` and `not-on-the-served-line` — the three a recorded corpus pin can be -# in against the corpus's merged main. A corpus is squash-merged, so a pin that is -# off the corpus's main line is a SQUASH-ADVANCE — `not-on-the-served-line` — -# whose one remedy is the same as `behind`'s: the consumer re-pins to the tip. It -# is NOT a divergence, and this report never calls it one. Two states of its own -# cover the cases it refuses to guess: `undecidable` (the corpus's history could -# not be deepened, so ancestry cannot be judged) and `unreadable` (the pin, or the -# corpus's merged main, could not be read). -# -# The producer-side half of the same question lives in opencharly/marketplace -# (`scripts/consumer-currency.sh`) and speaks the SAME vocabulary, state for -# state, so a reader sees one language on both sides of the pin. The two differ -# in where they stand, and that difference is deliberate: the producer judges -# from the corpus's OWN history and refuses to judge a shallow one, while this -# report judges from the consumer's checkout and DEEPENS it first (below) — the -# corpus's history is small, so the corpus-side answer is available instead of -# merely declared unavailable. -# -# THE JUDGMENT MUST BE DECIDABLE BEFORE IT IS REPORTED. `merge-base -# --is-ancestor` answers "not an ancestor" for a commit the clone does not have, -# which is indistinguishable from a real squash-advance — and the checkout of -# this submodule in CI IS a depth-1 clone: actions/checkout runs `git submodule -# update --init --force --depth=` with its default `fetch-depth: 1` -# (actions/checkout@v7, `src/git-command-manager.ts`, `submoduleUpdate`). A -# depth-1 history therefore cannot judge ancestry at all, and reporting from it -# would state a FALSE state — a divergence for a pin that is merely behind, with -# a wrong commit count. So a shallow corpus is DEEPENED first, and when the -# deepening cannot be done the report says `undecidable` and never guesses: a -# false state is worse than no report. -# -# Usage: check_corpus_currency.sh [] -# Prints exactly one line: -# corpus pin: is (merged main: ) -# Exit status is 0 in EVERY state, including a squash-advance, an undecidable -# history and a missing corpus: a report that could fail the build would be a -# gate, and this is not one. -set -u - -root=${1:-.} -corpus=${2:-marketplace} -dir="$root/$corpus" - -report() { - echo "corpus pin: $1 is $2 (merged main: $3)" -} - -# The pin is the superproject's INDEX entry — the gitlink it records — not the -# checkout's HEAD. A checkout that is not at the pin is a different question -# (and the checkout audit asks it). -if ! pinned=$(git -C "$root" rev-parse --verify -q "HEAD:$corpus" 2>/dev/null); then - report "(no pin)" "unreadable — the superproject records no gitlink for '$corpus'" "(unknown)" - exit 0 -fi - -if ! git -C "$dir" rev-parse --verify -q HEAD >/dev/null 2>&1; then - report "$pinned" "unreadable — the corpus has no checkout here, so its merged main could not be read" "(unknown)" - exit 0 -fi - -# The corpus's merged main, as the remote sees it right now. The fetch brings -# the tip's objects in, so the ancestry test below is decidable rather than -# unanswerable. -shallow=no -if [ "$(git -C "$dir" rev-parse --is-shallow-repository 2>/dev/null)" = "true" ]; then - shallow=yes -fi - -if [ "$shallow" = yes ]; then - # The history is too short to answer the question, so it is completed first. - # If it cannot be completed, the question is NOT answered — it is reported as - # undecidable. - if ! git -C "$dir" fetch --quiet --unshallow origin main >/dev/null 2>&1; then - report "$pinned" "undecidable — the corpus's history is shallow and could not be deepened, so ancestry cannot be judged" "(unknown)" - exit 0 - fi -else - if ! git -C "$dir" fetch --quiet origin main >/dev/null 2>&1; then - report "$pinned" "unreadable — the corpus's remote main could not be fetched" "(unknown)" - exit 0 - fi -fi -tip=$(git -C "$dir" rev-parse FETCH_HEAD) - -if git -C "$dir" merge-base --is-ancestor "$pinned" "$tip" 2>/dev/null; then - behind=$(git -C "$dir" rev-list --count "$pinned..$tip") - if [ "$behind" = 0 ]; then - state="cur — at the corpus's merged main" - else - state="behind — $behind commit(s) behind the corpus's merged main; an advance available NOW (a pin-bump PR in this repo)" - fi -else - state="not-on-the-served-line — the pin is not on the corpus's main line; its one remedy is the same as behind's (a pin-bump PR in this repo), and it is not a divergence" -fi - -report "$pinned" "$state" "$tip" -exit 0 diff --git a/.github/docs-corpus/test_check_corpus_currency.sh b/.github/docs-corpus/test_check_corpus_currency.sh deleted file mode 100644 index 496c148d..00000000 --- a/.github/docs-corpus/test_check_corpus_currency.sh +++ /dev/null @@ -1,247 +0,0 @@ -#!/usr/bin/env bash -# test_check_corpus_currency.sh — prove the currency REPORT is right, on fixtures. -# -# The report is the control that stops the NEXT drift: the drift gate cannot see a -# stale corpus (the pinned corpus regenerates its own old pages perfectly), so the -# workflow asks the second question and answers it. A report nobody checked is a -# comment, so every state the report can name is built here as a fixture and -# asserted EXACTLY: -# -# 1. the pin is at the corpus's merged main -> "cur — at the corpus's merged main" -# 2. the pin is behind it -> "behind — N commit(s) behind ..." -# 3. the pin is not on the corpus's main line -> "not-on-the-served-line ..." -# 4. the corpus has no checkout here -> "unreadable — ..." -# 5. the superproject records no gitlink -> "unreadable — ... no gitlink ..." -# 6. the corpus's remote main cannot be fetched -> "unreadable — ..." -# 7. the corpus's history is shallow and cannot -# be deepened -> "undecidable — ..." -# 8. the corpus is a DEPTH-1 checkout at a pin -# that IS behind — the shape CI has -> "behind — 2 commit(s) ..." -# -# Fixture 8 is the one that earns the rest: a depth-1 history cannot answer the -# ancestry question, so a report that judged from it would state a FALSE state — a -# divergence for a pin that is merely behind, with a wrong commit count. The -# checkout in CI IS a depth-1 clone (actions/checkout's `submodule update -# --depth=`, default 1), so this fixture is the CI shape, and the -# report must answer it truthfully. -# -# And the property that makes the report a report and NOT a gate: it exits 0 in -# EVERY case, including the squash-advance. A report that could fail a build -# would be a gate, and gating here would be red on every push until somebody ran -# the regeneration PR. -set -u - -here=$(cd "$(dirname "$0")" && pwd) -script="$here/check_corpus_currency.sh" -tmp=$(mktemp -d) -trap 'rm -rf "$tmp"' EXIT -fails=0 - -pass() { echo " PASS $1"; } -fail() { - fails=$((fails + 1)) - echo " FAIL $1" -} - -# A corpus origin with $2 commits on main (>= 1) and a divergent line on side. -mk_corpus() { - local base=$1 n=$2 i - mkdir -p "$base/work" - git init --quiet -b main "$base/work" - git -C "$base/work" config user.email test@example.invalid - git -C "$base/work" config user.name test - for i in $(seq 1 "$n"); do - echo "$i" >"$base/work/f$i" - git -C "$base/work" add "f$i" - git -C "$base/work" commit -qm "commit $i" - done - git init --quiet --bare "$base/origin.git" - # the bare origin's HEAD must name the branch the corpus publishes on, or a - # clone of it checks out nothing - git -C "$base/origin.git" symbolic-ref HEAD refs/heads/main - git -C "$base/work" remote add origin "$base/origin.git" - git -C "$base/work" push -q origin main - git -C "$base/work" checkout -q -b side - echo two >"$base/work/g" - git -C "$base/work" add g - git -C "$base/work" commit -qm side - git -C "$base/work" push -q origin side - git -C "$base/work" checkout -q main -} - -# A superproject whose `marketplace` gitlink records the given commit. -mk_super() { - local dir=$1 sha=$2 - mkdir -p "$dir" - git init --quiet -b main "$dir" - git -C "$dir" config user.email test@example.invalid - git -C "$dir" config user.name test - git -C "$dir" update-index --add --cacheinfo "160000,$sha,marketplace" - git -C "$dir" commit -qm pin -} - -# A superproject that records NO gitlink at all. -mk_super_without_pin() { - local dir=$1 - mkdir -p "$dir" - git init --quiet -b main "$dir" - git -C "$dir" config user.email test@example.invalid - git -C "$dir" config user.name test - echo nothing >"$dir/readme" - git -C "$dir" add readme - git -C "$dir" commit -qm none -} - -# A DEPTH-1 checkout of the corpus, sitting at $2 — the shape CI has. -# `file://` is required: a local-path clone ignores --depth. -mk_shallow_checkout() { - local base=$1 pin=$2 out=$3 - git clone --quiet --depth 1 -b main "file://$base/origin.git" "$out" - git -C "$out" fetch --quiet --depth 1 origin "$pin" - git -C "$out" checkout --quiet "$pin" -} - -run_report() { # $1 = superproject dir; prints the report, returns its exit code - local out rc - out=$(bash "$script" "$1" 2>&1) - rc=$? - echo "$out" - return $rc -} - -assert_state() { # $1 label, $2 expected substring, $3 actual output, $4 exit code - case "$3" in - *"$2"*) pass "$1" ;; - *) - fail "$1 — the report does not name the expected state" - echo " expected to contain: $2" - echo " got: $3" - ;; - esac - if [ "$4" = 0 ]; then - pass "$1 — the report exits 0 (a report must never fail the build)" - else - fail "$1 — the report exited $4; it must exit 0 in every state" - fi -} - -# The report must NEVER name a state the pin contract does not have. The retired -# wording called a squash-advance a "divergence" and sent the reader after the -# wrong remedy: the corpus is squash-merged, so a pin off the main line is a -# SQUASH-ADVANCE whose remedy is the same as `behind`'s. The fragments below are -# the instrument that detects the retired sentences; the retired sentences -# themselves live only in the pre-change tree, and the repo-wide sweep in the -# PR body greps for them and finds none. -assert_not_divergence() { # $1 label, $2 output - case "$2" in - *"divergence, not an advance"* | *"not an ancestor"*) - fail "$1 — the report still names the retired divergence wording" - echo " got: $2" - ;; - *) pass "$1 — the report does not call a squash-advance a divergence" ;; - esac -} - -# ── 1. the pin is at the corpus's merged main ────────────────────────────────────── -base="$tmp/a" -mk_corpus "$base" 1 -one=$(git -C "$base/work" rev-parse main) -mk_super "$tmp/a/super" "$one" -git clone --quiet -b main "$base/origin.git" "$tmp/a/super/marketplace" -out=$(run_report "$tmp/a/super") -rc=$? -assert_state "the pin is at the corpus's merged main" \ - "is cur — at the corpus's merged main (merged main: $one)" "$out" "$rc" -assert_not_divergence "the pin is at the corpus's merged main" "$out" - -# ── 2. the pin is one commit behind the corpus's merged main ────────────────────── -base="$tmp/b" -mk_corpus "$base" 2 -one=$(git -C "$base/work" rev-parse main~1) -mk_super "$tmp/b/super" "$one" -git clone --quiet -b main "$base/origin.git" "$tmp/b/super/marketplace" -out=$(run_report "$tmp/b/super") -rc=$? -assert_state "the pin is one commit behind" \ - "is behind — 1 commit(s) behind the corpus's merged main" "$out" "$rc" -assert_not_divergence "the pin is one commit behind" "$out" - -# ── 3. the pin is not on the corpus's main line (a squash-advance) ───────────────── -base="$tmp/c" -mk_corpus "$base" 1 -side=$(git -C "$base/work" rev-parse side) -mk_super "$tmp/c/super" "$side" -git clone --quiet -b main "$base/origin.git" "$tmp/c/super/marketplace" -out=$(run_report "$tmp/c/super") -rc=$? -assert_state "the pin is off the corpus's main line" \ - "is not-on-the-served-line — the pin is not on the corpus's main line" "$out" "$rc" -assert_not_divergence "the pin is off the corpus's main line" "$out" - -# ── 4. the corpus has no checkout here ─────────────────────────────────────────── -base="$tmp/d" -mk_corpus "$base" 1 -one=$(git -C "$base/work" rev-parse main) -mk_super "$tmp/d/super" "$one" -out=$(run_report "$tmp/d/super") -rc=$? -assert_state "the corpus is not materialized" \ - "is unreadable — the corpus has no checkout here" "$out" "$rc" - -# ── 5. the superproject records no gitlink ─────────────────────────────────────── -out=$(run_report "$tmp/e/super") -rc=$? -assert_state "the superproject records no corpus pin" \ - "is unreadable — the superproject records no gitlink for 'marketplace'" "$out" "$rc" -mk_super_without_pin "$tmp/e/super" -out=$(run_report "$tmp/e/super") -rc=$? -assert_state "the superproject records no corpus pin" \ - "is unreadable — the superproject records no gitlink for 'marketplace'" "$out" "$rc" - -# ── 6. the corpus's remote main cannot be fetched ───────────────────────────────── -base="$tmp/f" -mk_corpus "$base" 1 -one=$(git -C "$base/work" rev-parse main) -mk_super "$tmp/f/super" "$one" -git clone --quiet -b main "$base/origin.git" "$tmp/f/super/marketplace" -# the remote is gone: the fetch of the corpus's merged main must fail -git -C "$tmp/f/super/marketplace" remote set-url origin "$tmp/f/gone.git" -out=$(run_report "$tmp/f/super") -rc=$? -assert_state "the corpus's remote main cannot be fetched" \ - "is unreadable — the corpus's remote main could not be fetched" "$out" "$rc" - -# ── 7. the corpus's history is shallow and cannot be deepened ───────────────────── -base="$tmp/g" -mk_corpus "$base" 2 -one=$(git -C "$base/work" rev-parse main) -mk_super "$tmp/g/super" "$one" -mk_shallow_checkout "$base" "$one" "$tmp/g/super/marketplace" -git -C "$tmp/g/super/marketplace" remote set-url origin "$tmp/g/gone.git" -out=$(run_report "$tmp/g/super") -rc=$? -assert_state "the corpus's history is shallow and cannot be deepened" \ - "is undecidable — the corpus's history is shallow and could not be deepened" "$out" "$rc" - -# ── 8. the corpus is a DEPTH-1 checkout at a pin that IS behind ─────────────────── -# The CI shape. The pin is an ancestor of the corpus's merged main, so the report -# must say `behind` with the TRUE commit count — not a divergence, and not the -# wrong count a depth-1 history produces. -base="$tmp/h" -mk_corpus "$base" 3 -one=$(git -C "$base/work" rev-parse main~2) -mk_super "$tmp/h/super" "$one" -mk_shallow_checkout "$base" "$one" "$tmp/h/super/marketplace" -out=$(run_report "$tmp/h/super") -rc=$? -assert_state "the corpus is a depth-1 checkout at a pin that is behind" \ - "is behind — 2 commit(s) behind the corpus's merged main" "$out" "$rc" -assert_not_divergence "the corpus is a depth-1 checkout at a pin that is behind" "$out" - -if [ "$fails" -ne 0 ]; then - echo "test_check_corpus_currency: FAIL ($fails)" - exit 1 -fi -echo "test_check_corpus_currency: OK (every state is reported, and none of them fails)" -exit 0 diff --git a/.github/scripts/check_pin_currency.sh b/.github/scripts/check_pin_currency.sh new file mode 100644 index 00000000..df1f9bc6 --- /dev/null +++ b/.github/scripts/check_pin_currency.sh @@ -0,0 +1,231 @@ +#!/usr/bin/env bash +# check_pin_currency.sh — REPORT the currency of every SOURCE PIN the site consumes. +# It never fails. +# +# WHY THIS EXISTS. The site is generated from THREE pinned inputs: the guidance +# corpus (this repo's `marketplace` gitlink), the `charly` commit the deploy +# clones, and the umbrella commit the deploy clones. Every one of them is +# advanced by a MANUAL act after its producer lands, so the site trails its +# producers by however long nobody ran the regeneration — and the drift gate +# CANNOT see it: the PINNED sources regenerate their own (old) pages perfectly, +# so a stale pin is invisible to it. The drift gate answers "does the committed +# content match what the pinned inputs generate?" (yes, always); this answers the +# second question — "is each pinned input itself current?". +# +# THE ANSWER IS REPORTED, NEVER FAILED. A pin that is behind is an advance +# available NOW — the same shape the pin contract calls `behind`: a reportable +# state, not a broken edge. A gate that FAILED on it would be red on every push +# until somebody ran the regeneration PR, and the remedy is that PR, not a gate. +# +# THE STATES ARE THE PIN CONTRACT'S (umbrella AGENTS.md Part II rule 3): `cur`, +# `behind` and `not-on-the-served-line` — the three a recorded pin can be in +# against its producer's merged main. A pin that is off the producer's main line +# is a SQUASH-ADVANCE — `not-on-the-served-line` — whose one remedy is the same +# as `behind`'s: the consumer re-pins to the tip. It is NOT a divergence, and +# this report never calls it one. Two states of its own cover the cases it +# refuses to guess: `undecidable` (the history could not be deepened, so +# ancestry cannot be judged) and `unreadable` (the pin, or the producer's +# merged main, could not be read). +# +# The producer-side half of the same question lives in opencharly/marketplace +# (`scripts/consumer-currency.sh`) and speaks the SAME vocabulary, state for +# state, so a reader sees one language on both sides of the pin. +# +# THE JUDGMENT MUST BE DECIDABLE BEFORE IT IS REPORTED. `merge-base +# --is-ancestor` answers "not an ancestor" for a commit the clone does not have, +# which is indistinguishable from a real squash-advance — and the corpus +# checkout of this submodule in CI IS a depth-1 clone: actions/checkout runs +# `git submodule update --init --force --depth=` with its default +# `fetch-depth: 1` (actions/checkout@v7, `src/git-command-manager.ts`, +# `submoduleUpdate`). A depth-1 history therefore cannot judge ancestry at all, +# and reporting from it would state a FALSE state — a divergence for a pin that +# is merely behind, with a wrong commit count. So a shallow history is +# DEEPENED first, and when the deepening cannot be done the report says +# `undecidable` and never guesses: a false state is worse than no report. The +# same rule covers a pin whose commit is not in the history at all: the report +# says `unreadable`, because "not an ancestor" and "not here" are different +# facts and only one of them is a state. +# +# THE REPORT IS SELF-CONTAINED. It answers the question from THIS repository's +# own records — the committed corpus gitlink and the CI-time pins the workflow +# records — and reads each producer's history itself. It does not depend on the +# deploy's own checkouts, on where they live, or on the order the workflow +# happens to run its steps in: a control that reads another step's private state +# is a control that breaks when the step moves. +# +# THE PINS ARE RECORDED ONCE. The two CI-time pins live in the workflow's own +# `env:` block, which the deploy's clone step consumes and this report reads — +# one record, one occurrence of each SHA in the whole repository. The corpus +# pin is the committed gitlink the deploy checks out, and it is read from the +# commit's tree rather than from the checkout's HEAD: the checkout is a +# convenience, the tree entry is the pin. +# +# THE SCOPE IS THE SITE'S THREE SOURCE PINS, and the scope is stated here so a +# reader never has to guess it. The site also consumes RELEASE-TAG pins — the +# generator's own tag, and the per-plugin tags in the corpus wiring candy's +# pins file. Those are a DIFFERENT class of pin: their currency question is +# "is there a newer RELEASE?", not "is this commit behind the producer's +# merged main?", and the org has not given that question a state +# (opencharly/opencharly#793). So they are NAMED, MEASURED and FILED, not +# silently omitted — a pin that is invisible is the defect this report exists +# to end, and it does not end it by pretending a tag is a commit. +# +# Usage: check_pin_currency.sh [ []] +# Prints one line per pin: +# pin: is (merged main: ) +# Exit status is 0 in EVERY state, including a squash-advance, an undecidable +# history and a missing pin: a report that could fail the build would be a +# gate, and this is not one. +set -u + +root=${1:-.} +corpus=${2:-marketplace} +workflow="$root/.github/workflows/deploy.yml" + +report() { + echo "$1 pin: $2 is $3 (merged main: $4)" +} + +# The name each producer is called BY in a sentence. "the corpus" and "the +# umbrella" are common nouns and need their article; "charly" is a name and +# does not. The corpus's line is worded exactly as the corpus-only report +# worded it, so a reader who knows the old line reads the same words here. +producer_label() { + case "$1" in + corpus | umbrella) echo "the $1" ;; + *) echo "$1" ;; + esac +} + +# The value of one key of the workflow's own `env:` block — where the CI-time +# pins are recorded. An absent block, an absent key and an unreadable file all +# yield the empty string, which the callers report as `unreadable`. +# +# The value is everything after the key's colon, trimmed, with one layer of +# surrounding quotes removed: the block is YAML, and YAML may quote a value. +workflow_value() { + [ -f "$workflow" ] || return 0 + awk -v key="$1" ' + /^env:[[:space:]]*$/ { in_env = 1; next } + { + if (!in_env) next + if ($0 ~ /^[^[:space:]#]/) { in_env = 0; next } + line = $0 + sub(/^[[:space:]]+/, "", line) + if (index(line, key ":") != 1) next + v = substr(line, length(key) + 2) + gsub(/^[[:space:]]+|[[:space:]]+$/, "", v) + gsub(/^"|"$/, "", v) + gsub(/^\047|\047$/, "", v) + print v + exit + } + ' "$workflow" 2>/dev/null +} + +# judge +# +# The checkout must be a git repository with an `origin` remote. The judgement +# is made against the producer's merged main AS THE REMOTE SERVES IT NOW, so +# the fetch happens before the question is asked, and the question is asked +# only from a history that can answer it. +judge() { + local producer=$1 pin=$2 dir=$3 + local label tip behind state shallow + + label=$(producer_label "$producer") + + if ! git -C "$dir" cat-file -e "$pin^{commit}" 2>/dev/null; then + report "$producer" "$pin" \ + "unreadable — the pinned commit is not in $label's history, so its merged main could not be compared" \ + "(unknown)" + return 0 + fi + + shallow=no + if [ "$(git -C "$dir" rev-parse --is-shallow-repository 2>/dev/null)" = "true" ]; then + shallow=yes + fi + + if [ "$shallow" = yes ]; then + # The history is too short to answer the question, so it is completed first. + # If it cannot be completed, the question is NOT answered — it is reported + # as undecidable. + if ! git -C "$dir" fetch --quiet --unshallow origin main >/dev/null 2>&1; then + report "$producer" "$pin" \ + "undecidable — $label's history is shallow and could not be deepened, so ancestry cannot be judged" \ + "(unknown)" + return 0 + fi + else + if ! git -C "$dir" fetch --quiet origin main >/dev/null 2>&1; then + report "$producer" "$pin" \ + "unreadable — $label's remote main could not be fetched" "(unknown)" + return 0 + fi + fi + + tip=$(git -C "$dir" rev-parse FETCH_HEAD) + + if git -C "$dir" merge-base --is-ancestor "$pin" "$tip" 2>/dev/null; then + behind=$(git -C "$dir" rev-list --count "$pin..$tip") + if [ "$behind" = 0 ]; then + state="cur — at $label's merged main" + else + state="behind — $behind commit(s) behind $label's merged main; an advance available NOW (a pin-bump PR in this repo)" + fi + else + state="not-on-the-served-line — the pin is not on $label's main line; its one remedy is the same as behind's (a pin-bump PR in this repo), and it is not a divergence" + fi + + report "$producer" "$pin" "$state" "$tip" +} + +# ── the corpus gitlink ───────────────────────────────────────────────────────── +# The pin is the COMMITTED gitlink — the tree entry the deploy checks out — +# not the checkout's HEAD. A checkout that is not at the pin is a different +# question (and the drift gate asks it). +if ! pinned=$(git -C "$root" rev-parse --verify -q "HEAD:$corpus" 2>/dev/null); then + report "corpus" "(no pin)" \ + "unreadable — the superproject records no gitlink for '$corpus'" "(unknown)" +elif ! git -C "$root/$corpus" rev-parse --verify -q HEAD >/dev/null 2>&1; then + report "corpus" "$pinned" \ + "unreadable — the corpus has no checkout here, so its merged main could not be read" \ + "(unknown)" +else + judge "corpus" "$pinned" "$root/$corpus" +fi + +# ── the CI-time source pins ─────────────────────────────────────────────────── +# Each producer is read from the workflow's own `env:` block and judged against +# a checkout this report makes itself, so the judgement never depends on what +# the deploy happened to clone, or on where it put it. +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT + +for producer in charly umbrella; do + upper=$(printf '%s' "$producer" | tr '[:lower:]' '[:upper:]') + label=$(producer_label "$producer") + pin=$(workflow_value "${upper}_PIN") + url=$(workflow_value "${upper}_REPO") + if [ -z "$pin" ] || [ -z "$url" ]; then + report "$producer" "${pin:-(no pin)}" \ + "unreadable — $label's pin is not recorded in $workflow" "(unknown)" + continue + fi + dir="$tmp/$producer" + # A blobless clone — every commit and tree, no blobs: enough to judge + # ancestry, cheap enough to run on every push. NOT `--single-branch`: a pin + # that is off the producer's main line is a real state + # (`not-on-the-served-line`), and a single-branch clone would not hold that + # commit at all, so the report could not tell "off the line" from "not here". + if ! git clone --quiet --filter=blob:none --no-checkout "$url" "$dir" >/dev/null 2>&1; then + report "$producer" "$pin" \ + "unreadable — $label's repository could not be cloned, so its merged main could not be read" \ + "(unknown)" + continue + fi + judge "$producer" "$pin" "$dir" +done + +exit 0 diff --git a/.github/scripts/test_check_pin_currency.sh b/.github/scripts/test_check_pin_currency.sh new file mode 100644 index 00000000..b6bd0058 --- /dev/null +++ b/.github/scripts/test_check_pin_currency.sh @@ -0,0 +1,401 @@ +#!/usr/bin/env bash +# test_check_pin_currency.sh — prove the currency REPORT is right, on fixtures. +# +# The report is the control that stops the NEXT drift: the drift gate cannot see +# a stale pin (the pinned sources regenerate their own old pages perfectly), so +# the workflow asks the second question and answers it. A report nobody checked +# is a comment, so every state the report can name is built here as a fixture +# and asserted EXACTLY: +# +# 1. the pin is at the corpus's merged main -> "cur — at ...'s merged main" +# 2. the pin is behind it -> "behind — N commit(s) behind ..." +# 3. the pin is not on the corpus's main line -> "not-on-the-served-line ..." +# 4. the corpus has no checkout here -> "unreadable — ..." +# 5. the superproject records no gitlink -> "unreadable — ... no gitlink ..." +# 6. the corpus's remote main cannot be fetched -> "unreadable — ..." +# 7. the corpus's history is shallow and cannot +# be deepened -> "undecidable — ..." +# 8. the corpus is a DEPTH-1 checkout at a pin +# that IS behind — the shape CI has -> "behind — 2 commit(s) ..." +# 9. a CI-TIME pin at its producer's merged main -> "cur — ..." +# 10. a CI-TIME pin behind its producer's main -> "behind — N commit(s) ..." +# 11. the workflow records no pin for a producer -> "unreadable — ... not recorded ..." +# 12. the producer's repository cannot be cloned -> "unreadable — ... could not be cloned ..." +# 13. the CI-TIME pin is not in the history -> "unreadable — ... not in ...'s history ..." +# 14. all three pins recorded -> EXACTLY three lines, one per pinned input. +# +# Fixture 8 is the one that earns the rest: a depth-1 history cannot answer the +# ancestry question, so a report that judged from it would state a FALSE state — +# a divergence for a pin that is merely behind, with a wrong commit count. The +# checkout in CI IS a depth-1 clone (actions/checkout's `submodule update +# --depth=`, default 1), so this fixture is the CI shape, and the +# report must answer it truthfully. +# +# Fixture 14 is the one that keeps the report honest about its SCOPE: the whole +# point of this report is that it watches EVERY pinned input, so a change that +# quietly stopped reporting one of them would leave the site exactly as +# unobserved as it was before this report existed, with every other fixture +# still green. +# +# And the property that makes the report a report and NOT a gate: it exits 0 in +# EVERY case, including the squash-advance. A report that could fail a build +# would be a gate, and gating here would be red on every push until somebody ran +# the regeneration PR. +set -u + +here=$(cd "$(dirname "$0")" && pwd) +script="$here/check_pin_currency.sh" +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT +fails=0 + +pass() { echo " PASS $1"; } +fail() { + fails=$((fails + 1)) + echo " FAIL $1" +} + +# A producer origin with $2 commits on main (>= 1) and a divergent line on side. +mk_corpus() { + local base=$1 n=$2 i + mkdir -p "$base/work" + git init --quiet -b main "$base/work" + git -C "$base/work" config user.email test@example.invalid + git -C "$base/work" config user.name test + for i in $(seq 1 "$n"); do + echo "$i" >"$base/work/f$i" + git -C "$base/work" add "f$i" + git -C "$base/work" commit -qm "commit $i" + done + git init --quiet --bare "$base/origin.git" + # the bare origin's HEAD must name the branch the corpus publishes on, or a + # clone of it checks out nothing + git -C "$base/origin.git" symbolic-ref HEAD refs/heads/main + git -C "$base/work" remote add origin "$base/origin.git" + git -C "$base/work" push -q origin main + git -C "$base/work" checkout -q -b side + echo two >"$base/work/g" + git -C "$base/work" add g + git -C "$base/work" commit -qm side + git -C "$base/work" push -q origin side + git -C "$base/work" checkout -q main +} + +# A superproject whose `marketplace` gitlink records the given commit. +mk_super() { + local dir=$1 sha=$2 + mkdir -p "$dir" + git init --quiet -b main "$dir" + git -C "$dir" config user.email test@example.invalid + git -C "$dir" config user.name test + git -C "$dir" update-index --add --cacheinfo "160000,$sha,marketplace" + git -C "$dir" commit -qm pin +} + +# A superproject that records NO gitlink at all. +mk_super_without_pin() { + local dir=$1 + mkdir -p "$dir" + git init --quiet -b main "$dir" + git -C "$dir" config user.email test@example.invalid + git -C "$dir" config user.name test + echo nothing >"$dir/readme" + git -C "$dir" add readme + git -C "$dir" commit -qm none +} + +# A DEPTH-1 checkout of the corpus, sitting at $2 — the shape CI has. +# `file://` is required: a local-path clone ignores --depth. +mk_shallow_checkout() { + local base=$1 pin=$2 out=$3 + git clone --quiet --depth 1 -b main "file://$base/origin.git" "$out" + git -C "$out" fetch --quiet --depth 1 origin "$pin" + git -C "$out" checkout --quiet "$pin" +} + +# The workflow that RECORDS the CI-time pins — the same `env:` block the deploy +# reads. Written into the superproject, because that is where the report looks. +# An empty repo/pin pair is written as an empty value, which is what a +# workflow that records no pin for that producer holds. +mk_workflow() { + local super=$1 charly_repo=$2 charly_pin=$3 umbrella_repo=$4 umbrella_pin=$5 + mkdir -p "$super/.github/workflows" + cat >"$super/.github/workflows/deploy.yml" <&1) + rc=$? + echo "$out" + return $rc +} + +assert_state() { # $1 label, $2 expected substring, $3 actual output, $4 exit code + case "$3" in + *"$2"*) pass "$1" ;; + *) + fail "$1 — the report does not name the expected state" + echo " expected to contain: $2" + echo " got: $3" + ;; + esac + if [ "$4" = 0 ]; then + pass "$1 — the report exits 0 (a report must never fail the build)" + else + fail "$1 — the report exited $4; it must exit 0 in every state" + fi +} + +# The report must NEVER name a state the pin contract does not have. The retired +# wording called a squash-advance a "divergence" and sent the reader after the +# wrong remedy: the producers are squash-merged, so a pin off the main line is +# a SQUASH-ADVANCE whose remedy is the same as `behind`'s. The fragments below +# are the instrument that detects the retired sentences; the retired sentences +# themselves live only in the pre-change tree, and the repo-wide sweep in the +# PR body greps for them and finds none. +assert_not_divergence() { # $1 label, $2 output + case "$2" in + *"divergence, not an advance"* | *"not an ancestor"*) + fail "$1 — the report still names the retired divergence wording" + echo " got: $2" + ;; + *) pass "$1 — the report does not call a squash-advance a divergence" ;; + esac +} + +# Every pinned input the report watches must be REPORTED — a pin that is +# silently skipped is a pin nobody watches. +assert_reported() { # $1 label, $2 expected line prefix, $3 output + if printf '%s\n' "$3" | grep -q "^$2"; then + pass "$1" + else + fail "$1 — the report says nothing about this pin" + echo " expected a line starting: $2" + echo " got: $3" + fi +} + +# ── 1. the pin is at the corpus's merged main ────────────────────────────────────── +base="$tmp/a" +mk_corpus "$base" 1 +one=$(git -C "$base/work" rev-parse main) +mk_super "$tmp/a/super" "$one" +git clone --quiet -b main "$base/origin.git" "$tmp/a/super/marketplace" +out=$(run_report "$tmp/a/super") +rc=$? +assert_state "the pin is at the corpus's merged main" \ + "is cur — at the corpus's merged main (merged main: $one)" "$out" "$rc" +assert_not_divergence "the pin is at the corpus's merged main" "$out" + +# ── 2. the pin is one commit behind the corpus's merged main ────────────────────── +base="$tmp/b" +mk_corpus "$base" 2 +one=$(git -C "$base/work" rev-parse main~1) +mk_super "$tmp/b/super" "$one" +git clone --quiet -b main "$base/origin.git" "$tmp/b/super/marketplace" +out=$(run_report "$tmp/b/super") +rc=$? +assert_state "the pin is one commit behind" \ + "is behind — 1 commit(s) behind the corpus's merged main" "$out" "$rc" +assert_not_divergence "the pin is one commit behind" "$out" + +# ── 3. the pin is not on the corpus's main line (a squash-advance) ───────────────── +base="$tmp/c" +mk_corpus "$base" 1 +side=$(git -C "$base/work" rev-parse side) +mk_super "$tmp/c/super" "$side" +git clone --quiet -b main "$base/origin.git" "$tmp/c/super/marketplace" +out=$(run_report "$tmp/c/super") +rc=$? +assert_state "the pin is off the corpus's main line" \ + "is not-on-the-served-line — the pin is not on the corpus's main line" "$out" "$rc" +assert_not_divergence "the pin is off the corpus's main line" "$out" + +# ── 4. the corpus has no checkout here ─────────────────────────────────────────── +base="$tmp/d" +mk_corpus "$base" 1 +one=$(git -C "$base/work" rev-parse main) +mk_super "$tmp/d/super" "$one" +out=$(run_report "$tmp/d/super") +rc=$? +assert_state "the corpus is not materialized" \ + "is unreadable — the corpus has no checkout here" "$out" "$rc" + +# ── 5. the superproject records no corpus gitlink ───────────────────────────────── +mk_super_without_pin "$tmp/e/super" +out=$(run_report "$tmp/e/super") +rc=$? +assert_state "the superproject records no corpus pin" \ + "is unreadable — the superproject records no gitlink for 'marketplace'" "$out" "$rc" + +# ── 6. the corpus's remote main cannot be fetched ───────────────────────────────── +base="$tmp/f" +mk_corpus "$base" 1 +one=$(git -C "$base/work" rev-parse main) +mk_super "$tmp/f/super" "$one" +git clone --quiet -b main "$base/origin.git" "$tmp/f/super/marketplace" +# the remote is gone: the fetch of the corpus's merged main must fail +git -C "$tmp/f/super/marketplace" remote set-url origin "$tmp/f/gone.git" +out=$(run_report "$tmp/f/super") +rc=$? +assert_state "the corpus's remote main cannot be fetched" \ + "is unreadable — the corpus's remote main could not be fetched" "$out" "$rc" + +# ── 7. the corpus's history is shallow and cannot be deepened ───────────────────── +base="$tmp/g" +mk_corpus "$base" 2 +one=$(git -C "$base/work" rev-parse main) +mk_super "$tmp/g/super" "$one" +mk_shallow_checkout "$base" "$one" "$tmp/g/super/marketplace" +git -C "$tmp/g/super/marketplace" remote set-url origin "$tmp/g/gone.git" +out=$(run_report "$tmp/g/super") +rc=$? +assert_state "the corpus's history is shallow and cannot be deepened" \ + "is undecidable — the corpus's history is shallow and could not be deepened" "$out" "$rc" + +# ── 8. the corpus is a DEPTH-1 checkout at a pin that IS behind ─────────────────── +# The CI shape. The pin is an ancestor of the corpus's merged main, so the report +# must say `behind` with the TRUE commit count — not a divergence, and not the +# wrong count a depth-1 history produces. +base="$tmp/h" +mk_corpus "$base" 3 +one=$(git -C "$base/work" rev-parse main~2) +mk_super "$tmp/h/super" "$one" +mk_shallow_checkout "$base" "$one" "$tmp/h/super/marketplace" +out=$(run_report "$tmp/h/super") +rc=$? +assert_state "the corpus is a depth-1 checkout at a pin that is behind" \ + "is behind — 2 commit(s) behind the corpus's merged main" "$out" "$rc" +assert_not_divergence "the corpus is a depth-1 checkout at a pin that is behind" "$out" + +# ── 9. a CI-TIME pin at its producer's merged main ──────────────────────────────── +# The corpus pin is `cur`, and so is the charly pin — the report names BOTH, one +# line each, in the same vocabulary. +base="$tmp/i" +mk_corpus "$base" 1 +corpus_pin=$(git -C "$base/work" rev-parse main) +mk_corpus "$tmp/i/charly" 1 +charly_pin=$(git -C "$tmp/i/charly/work" rev-parse main) +mk_super "$tmp/i/super" "$corpus_pin" +git clone --quiet -b main "$base/origin.git" "$tmp/i/super/marketplace" +mk_workflow "$tmp/i/super" "$tmp/i/charly/origin.git" "$charly_pin" "" "" +out=$(run_report "$tmp/i/super") +rc=$? +assert_state "the CI-time charly pin is at its producer's merged main" \ + "charly pin: $charly_pin is cur — at charly's merged main (merged main: $charly_pin)" "$out" "$rc" +assert_reported "the corpus pin is reported alongside it" "corpus pin: " "$out" +assert_not_divergence "the CI-time charly pin is at its producer's merged main" "$out" + +# ── 10. a CI-TIME pin behind its producer's merged main ─────────────────────────── +base="$tmp/j" +mk_corpus "$base" 1 +corpus_pin=$(git -C "$base/work" rev-parse main) +mk_corpus "$tmp/j/umbrella" 3 +umbrella_pin=$(git -C "$tmp/j/umbrella/work" rev-parse main~2) +mk_super "$tmp/j/super" "$corpus_pin" +git clone --quiet -b main "$base/origin.git" "$tmp/j/super/marketplace" +mk_workflow "$tmp/j/super" "" "" "$tmp/j/umbrella/origin.git" "$umbrella_pin" +out=$(run_report "$tmp/j/super") +rc=$? +assert_state "the CI-time umbrella pin is behind its producer's merged main" \ + "umbrella pin: $umbrella_pin is behind — 2 commit(s) behind the umbrella's merged main" "$out" "$rc" +assert_reported "the charly pin is reported even when it records none" "charly pin: " "$out" +assert_not_divergence "the CI-time umbrella pin is behind its producer's merged main" "$out" + +# ── 11. the workflow records no pin for a producer ───────────────────────────────── +base="$tmp/k" +mk_corpus "$base" 1 +corpus_pin=$(git -C "$base/work" rev-parse main) +mk_super "$tmp/k/super" "$corpus_pin" +git clone --quiet -b main "$base/origin.git" "$tmp/k/super/marketplace" +mk_workflow "$tmp/k/super" "" "" "" "" +out=$(run_report "$tmp/k/super") +rc=$? +assert_state "the workflow records no charly pin" \ + "charly pin: (no pin) is unreadable — charly's pin is not recorded in" "$out" "$rc" +assert_state "the workflow records no umbrella pin" \ + "umbrella pin: (no pin) is unreadable — the umbrella's pin is not recorded in" "$out" "$rc" + +# ── 12. the producer's repository cannot be cloned ───────────────────────────────── +base="$tmp/l" +mk_corpus "$base" 1 +corpus_pin=$(git -C "$base/work" rev-parse main) +mk_super "$tmp/l/super" "$corpus_pin" +git clone --quiet -b main "$base/origin.git" "$tmp/l/super/marketplace" +mk_workflow "$tmp/l/super" "$tmp/l/gone.git" "0000000000000000000000000000000000000000" "" "" +out=$(run_report "$tmp/l/super") +rc=$? +assert_state "the producer's repository cannot be cloned" \ + "charly pin: 0000000000000000000000000000000000000000 is unreadable — charly's repository could not be cloned" "$out" "$rc" + +# ── 13. the CI-TIME pin is not in the producer's history ────────────────────────── +# "not an ancestor" and "not here" are different facts, and only one of them is +# a state: a pin that is not in the history at all must not be reported as a +# squash-advance. +base="$tmp/m" +mk_corpus "$base" 1 +corpus_pin=$(git -C "$base/work" rev-parse main) +mk_corpus "$tmp/m/charly" 1 +mk_super "$tmp/m/super" "$corpus_pin" +git clone --quiet -b main "$base/origin.git" "$tmp/m/super/marketplace" +mk_workflow "$tmp/m/super" "$tmp/m/charly/origin.git" \ + "1111111111111111111111111111111111111111" "" "" +out=$(run_report "$tmp/m/super") +rc=$? +assert_state "the CI-time pin is not in the producer's history" \ + "is unreadable — the pinned commit is not in charly's history" "$out" "$rc" + +# ── 14. every pinned input is reported, one line each ───────────────────────────── +# The report's whole claim is that it watches EVERY pinned input the site +# consumes. A change that stopped reporting one of them would leave the site as +# unobserved as it was before this report existed — with every other fixture +# still green — so the COUNT is asserted here, not just the states. +base="$tmp/n" +mk_corpus "$base" 1 +corpus_pin=$(git -C "$base/work" rev-parse main) +mk_corpus "$tmp/n/charly" 1 +charly_pin=$(git -C "$tmp/n/charly/work" rev-parse main) +mk_corpus "$tmp/n/umbrella" 1 +umbrella_pin=$(git -C "$tmp/n/umbrella/work" rev-parse main) +mk_super "$tmp/n/super" "$corpus_pin" +git clone --quiet -b main "$base/origin.git" "$tmp/n/super/marketplace" +mk_workflow "$tmp/n/super" "$tmp/n/charly/origin.git" "$charly_pin" \ + "$tmp/n/umbrella/origin.git" "$umbrella_pin" +out=$(run_report "$tmp/n/super") +rc=$? +lines=$(printf '%s\n' "$out" | grep -c " pin: ") +if [ "$lines" = 3 ]; then + pass "the report names all three pinned inputs — one line each" +else + fail "the report names $lines pinned inputs; it must name all three" + echo " got: $out" +fi +assert_reported "the corpus pin is reported" "corpus pin: " "$out" +assert_reported "the charly pin is reported" "charly pin: " "$out" +assert_reported "the umbrella pin is reported" "umbrella pin: " "$out" + +if [ "$fails" -ne 0 ]; then + echo "test_check_pin_currency: FAIL ($fails)" + exit 1 +fi +echo "test_check_pin_currency: OK (every state is reported, and none of them fails)" +exit 0 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e2777717..501763fc 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -16,11 +16,12 @@ # 4. FAILS if the committed content does not match what the pinned charly generates # (the drift gate: regeneration on a clean tree is a no-op, so any diff means a # docs PR must bump the charly CI-time commit and carry the regenerated pages), -# 5. REPORTS whether the pinned marketplace corpus is behind the corpus's merged -# main — reported, never failed: a corpus that is behind is an advance -# available now, and the remedy is a regeneration PR that bumps the pin, not a -# gate (the drift gate above cannot see a stale corpus, because the PINNED -# corpus regenerates its own old pages perfectly), +# 5. REPORTS whether each of the site's THREE pinned source inputs — the +# marketplace corpus, the charly commit and the umbrella commit — is behind +# its producer's merged main. Reported, never failed: a pin that is behind is +# an advance available now, and the remedy is a regeneration PR that bumps the +# pin, not a gate (the drift gate above cannot see a stale pin, because the +# PINNED sources regenerate their own old pages perfectly), # 6. builds the Astro site and deploys to Cloudflare Pages. # # WHY A WORKFLOW RATHER THAN CLOUDFLARE'S GIT INTEGRATION: connecting a Cloudflare Pages project @@ -51,6 +52,19 @@ concurrency: permissions: contents: read +# THE SOURCE PINS, RECORDED ONCE. The site's generated half is a projection of +# three pinned inputs, and every one of them is advanced by a MANUAL act after +# its producer lands. These two CI-time commits are recorded HERE, once, and +# this single record is consumed by the clone step below and read by the +# pin-currency report — so a SHA can never be written in one place and +# forgotten in the other. The corpus pin is the `marketplace` gitlink, which is +# a gitlink by nature and needs no record here. +env: + CHARLY_REPO: https://github.com/opencharly/charly.git + CHARLY_PIN: be7a505f476c1a5b0302d878e0b5686a2cde3e07 + UMBRELLA_REPO: https://github.com/opencharly/opencharly.git + UMBRELLA_PIN: 1c88fcf15f8fb9dd8b2814210472a63d3a79d0e2 + jobs: deploy: runs-on: ubuntu-latest @@ -78,7 +92,7 @@ jobs: # `fetch-depth` is left at its default (1), so the corpus submodule is # a DEPTH-1 clone: actions/checkout runs `git submodule update --init # --force --depth=` (actions/checkout@v7, - # `src/git-command-manager.ts`, `submoduleUpdate`). The corpus-currency + # `src/git-command-manager.ts`, `submoduleUpdate`). The pin-currency # report below therefore deepens the corpus's history before it judges # ancestry — a depth-1 history cannot answer that question. submodules: recursive @@ -120,20 +134,21 @@ jobs: run: python3 .github/scripts/test_check_step_timeouts.py timeout-minutes: 5 - - name: Test the corpus-currency report + - name: Test the pin-currency report timeout-minutes: 5 - run: bash .github/docs-corpus/test_check_corpus_currency.sh + run: bash .github/scripts/test_check_pin_currency.sh - - name: Report the corpus pin's currency + - name: Report each pinned input's currency timeout-minutes: 10 - # The corpus pin is advanced by a MANUAL act after the corpus lands, so the - # site trails the corpus by however long nobody ran the regeneration — and - # the drift gate further down CANNOT see it: the PINNED corpus generates its - # own (old) pages perfectly, so a stale corpus is invisible to it. + # EVERY pinned input is advanced by a MANUAL act after its producer lands, so + # the site trails its producers by however long nobody ran the regeneration — + # and the drift gate further down CANNOT see it: the PINNED sources generate + # their own (old) pages perfectly, so a stale pin is invisible to it. That + # blind spot is not the corpus's alone; it is the charly pin's and the + # umbrella pin's exactly as much, and the drift gate is blind to all three. # - # This step asks the second question the workflow can answer from what it - # already has: is the pinned corpus behind the corpus's merged main? The - # answer is REPORTED, never failed — a corpus that is behind is an advance + # This step asks the second question: is each pinned input itself current? + # The answer is REPORTED, never failed — a pin that is behind is an advance # available NOW, the same shape the pin contract calls `behind`: a # reportable state, not a broken edge. A workflow that FAILED on it would be # red on every push until somebody ran the regeneration PR, and the remedy is @@ -145,13 +160,17 @@ jobs: # corpus checkout here is a depth-1 clone (the checkout step above), so the # report deepens it first and says `undecidable` when it cannot. A report # that stated a state it could not establish would be worse than no report. + # + # The report reads the CI-time pins from this workflow's own `env:` block + # and judges each producer's history itself, so it does not depend on the + # deploy's own checkouts or on the order the steps run in. run: | set -o pipefail - bash .github/docs-corpus/check_corpus_currency.sh . | tee /tmp/corpus-currency.txt + bash .github/scripts/check_pin_currency.sh . | tee /tmp/pin-currency.txt { - echo "### corpus pin" + echo "### pinned inputs" echo "" - cat /tmp/corpus-currency.txt + cat /tmp/pin-currency.txt } >>"$GITHUB_STEP_SUMMARY" - name: Fetch the pinned charly source (CI-time temp checkout, recursive for box/*) @@ -161,12 +180,12 @@ jobs: # submodules: --recursive at clone time pulls each box at its default-branch HEAD, # but the committed docs content was generated against the box commits the pinned # charly checkout records — checkout-then-init pins them exactly. - git clone https://github.com/opencharly/charly.git /tmp/charly && git -C /tmp/charly checkout bafd8dbc3110904872831998fb4caa701cc2990c && git -C /tmp/charly submodule update --init --recursive + git clone "$CHARLY_REPO" /tmp/charly && git -C /tmp/charly checkout "$CHARLY_PIN" && git -C /tmp/charly submodule update --init --recursive # The four root narratives (SOUL.md/VISION.md/GRIEVANCES.md/LIBERATION.md) moved # from the charly root to the UMBRELLA root (opencharly/opencharly#357); the # generator reads them from the umbrella checkout passed as --narrative below. # No submodule init — only the root files are read. - git clone https://github.com/opencharly/opencharly.git /tmp/umbrella && git -C /tmp/umbrella checkout e631aacf32df4e26a66f2cb6a75fc9e85e212399 + git clone "$UMBRELLA_REPO" /tmp/umbrella && git -C /tmp/umbrella checkout "$UMBRELLA_PIN" - uses: actions/setup-node@v7 timeout-minutes: 10 diff --git a/AGENTS.md b/AGENTS.md index 494948bb..07997d8e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,7 +12,7 @@ Canonical files: - the repo's generation workflow (`.github/workflows/`) — the SOLE owner of generation, the drift gate and the Cloudflare Pages deploy; the pinned charly - commit lives there. + and umbrella commits live there, in its own `env:` block. - `astro.config.mjs` — the Starlight config; its sidebar `link:` targets are resolved against the emitted routes by generation (a dead one fails the run). - `package.json` — the Astro/Starlight toolchain and the `astro build` script. @@ -45,22 +45,27 @@ Canonical files: and every PR: clone the pinned charly, build the binary, regenerate the generated half, FAIL on any drift, build Astro, deploy. A drift failure means a regeneration must land. -- The workflow also **REPORTS the corpus pin's currency** — whether the pinned - `marketplace` commit is behind the corpus's merged main. It is reported, never - failed: a corpus that is behind is an advance available now, and the remedy is - a regeneration PR that bumps the pin, not a gate. The drift gate cannot see - this on its own — the PINNED corpus regenerates its own (old) pages perfectly, - so a stale corpus is invisible to it. +- The workflow also **REPORTS each pinned input's currency** — whether the + pinned `marketplace` commit, the pinned `charly` commit and the pinned + umbrella commit are behind their producers' merged mains. It is reported, + never failed: a pin that is behind is an advance available now, and the + remedy is a regeneration PR that bumps the pin, not a gate. The drift gate + cannot see this on its own — the PINNED sources regenerate their own (old) + pages perfectly, so a stale pin is invisible to it. The two CI-time commits + are recorded once, in the workflow's own `env:` block, which both the clone + step and the report read (`.github/scripts/check_pin_currency.sh`); the + report's own fixtures are `.github/scripts/test_check_pin_currency.sh`. ## Modify this repo - Hand-authored pages (`start/`, `concepts/`, `guides/`) are edited here directly. - Generated pages are never edited here: `index.md` projects the charly - `README.md`; `grievances`/`vision`/`liberation` project charly's root files; - `reference/**` projects the pinned charly checkout; `recipes/**` projects the - marketplace corpus. Edit the source, then land a regeneration PR here that - bumps the pinned charly commit — and, for a corpus change, the pinned - `marketplace` commit — and carries the regenerated pages. + `README.md`; `grievances`/`vision`/`liberation`/`soul` project the umbrella's + root files; `reference/**` projects the pinned charly checkout; `recipes/**` + projects the marketplace corpus. Edit the source, then land a regeneration PR + here that bumps the pinned charly commit — the pinned umbrella commit, for a + narrative change, and the pinned `marketplace` commit, for a corpus change — + and carries the regenerated pages. - The home page is one of the generated ones — to change the front page, change the charly `README.md`. diff --git a/src/content/docs/index.md b/src/content/docs/index.md index 8c3a730a..651dd97b 100644 --- a/src/content/docs/index.md +++ b/src/content/docs/index.md @@ -63,7 +63,7 @@ it — and hands the whole loop to your agents through the same CLI you use. ```mermaid flowchart LR C["your candy list
(charly.yml)"] --> P["install plan
(one target-neutral form)"] - P --> pod["pod
podman · docker · nerdctl"] + P --> pod["pod
podman · docker · containerd"] P --> vm["vm
rootless libvirt"] P --> local["local
this host or SSH"] P --> android["android
device or emulator"] @@ -78,7 +78,7 @@ flowchart LR |---|---|---| | **Build** | Multi-stage Containerfiles from a candy list; images that carry their own capabilities and tests as `ai.opencharly.*` labels | `box build` `box validate` `box reconcile` · builders `pixi` `npm` `cargo` `aur` `mise` | | **Distros** | Ready-made base boxes and coder boxes with the AI coding CLIs, runtimes and nested containers | fedora · arch · cachyos · debian · ubuntu · omarchy | -| **Engines & init** | Run on podman, docker or nerdctl, chosen per host for building and running; declare a `service:` once and charly composes the init the destination needs | `podman` `docker` `nerdctl` · supervisord · systemd · OpenRC | +| **Engines & init** | Run on podman, docker or containerd, chosen per host for building and running; declare a `service:` once and charly composes the init the destination needs | `podman` `docker` `containerd` · supervisord · systemd · OpenRC | | **Deploy** | Seven substrates, sidecars, Tailscale/Cloudflare tunnels, encrypted volumes, reversible host installs | `deploy add` `deploy del` `start` `stop` `config` | | **VMs** | Rootless libvirt guests from seven sources, cloud-init, UEFI/Secure Boot, snapshots, GPU passthrough with a preemption arbiter | `charly vm` · `libvirt:` `spice:` | | **Kubernetes** | Kustomize + Helm deploys, kind clusters, k3s inside a VM, the KubeVirt platform | `kubernetes:` `kindcluster:` `kubevirt:` · `kube:` `helm:` | @@ -289,7 +289,7 @@ each word to whichever one claims it; there is no `pod` case in a switch stateme | **command** — `charly` subcommands | `deploy` `check` `vm` `mcp` `agent` | | **step** — install operations | `service-custom` `helm-release` `reboot` | | **builder** — multi-stage build patterns | `pixi` `npm` `cargo` `aur` `mise` | -| **engine** — container engines | `podman` `docker` `nerdctl` | +| **engine** — container engines | `podman` `docker` `containerd` | You extend charly by writing candies — in your own repo, referenced by git URL — and a substrate you invent is the same kind of thing as `pod:`. The [provider index](/reference/providers/) diff --git a/src/content/docs/reference/box/arch/arch-builder.md b/src/content/docs/reference/box/arch/arch-builder.md index 4fed076f..39166796 100644 --- a/src/content/docs/reference/box/arch/arch-builder.md +++ b/src/content/docs/reference/box/arch/arch-builder.md @@ -18,3 +18,4 @@ This box composes: - `@github.com/opencharly/layer-nodejs:v2026.272.0322` - `@github.com/opencharly/layer-build-toolchain:v2026.271.1840` - `@github.com/opencharly/layer-yay:v2026.272.0425` +- `arch-skills` diff --git a/src/content/docs/reference/box/arch/arch-coder.md b/src/content/docs/reference/box/arch/arch-coder.md index f6eca33a..af333566 100644 --- a/src/content/docs/reference/box/arch/arch-coder.md +++ b/src/content/docs/reference/box/arch/arch-coder.md @@ -40,3 +40,4 @@ This box composes: - `@github.com/opencharly/layer-github-actions:v2026.272.0135` - `@github.com/opencharly/layer-google-cloud-npm:v2026.273.1835` - `@github.com/opencharly/layer-grafana-tools:v2026.272.0139` +- `arch-skills` diff --git a/src/content/docs/reference/box/arch/arch-test.md b/src/content/docs/reference/box/arch/arch-test.md index ad47e382..eb557446 100644 --- a/src/content/docs/reference/box/arch/arch-test.md +++ b/src/content/docs/reference/box/arch/arch-test.md @@ -17,3 +17,4 @@ This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `arch-pac-test` - `arch-aur-test` +- `arch-skills` diff --git a/src/content/docs/reference/box/arch/arch.md b/src/content/docs/reference/box/arch/arch.md index c5272340..fce63e4c 100644 --- a/src/content/docs/reference/box/arch/arch.md +++ b/src/content/docs/reference/box/arch/arch.md @@ -8,3 +8,10 @@ title: "arch" |---|---| | **Repo** | `box/arch` | | **Base** | `quay.io/archlinux/archlinux:base-20260719.0.558306` | + + +## Composition + +This box composes: + +- `arch-skills` diff --git a/src/content/docs/reference/box/arch/charly-arch.md b/src/content/docs/reference/box/arch/charly-arch.md index 678effa0..3387ea72 100644 --- a/src/content/docs/reference/box/arch/charly-arch.md +++ b/src/content/docs/reference/box/arch/charly-arch.md @@ -20,4 +20,5 @@ This box composes: - `@github.com/opencharly/layer-gh:v2026.272.0136` - `@github.com/opencharly/pod-sshd:v2026.272.0324` - `@github.com/opencharly/layer-container-nesting:v2026.271.2309` -- `@github.com/opencharly/layer-nvidia:v2026.271.1817` +- `@github.com/opencharly/layer-nvidia:v2026.289.1705` +- `arch-skills` diff --git a/src/content/docs/reference/box/arch/cuda-arch-builder.md b/src/content/docs/reference/box/arch/cuda-arch-builder.md index f9632611..9be9b0ac 100644 --- a/src/content/docs/reference/box/arch/cuda-arch-builder.md +++ b/src/content/docs/reference/box/arch/cuda-arch-builder.md @@ -14,5 +14,5 @@ title: "cuda-arch-builder" This box composes: -- `@github.com/opencharly/layer-cuda:v2026.274.0643` +- `@github.com/opencharly/layer-cuda:v2026.290.1513` - `@github.com/opencharly/layer-nvenc-headers:v2026.272.0603` diff --git a/src/content/docs/reference/box/cachyos/cachyos-pacstrap-builder.md b/src/content/docs/reference/box/cachyos/cachyos-pacstrap-builder.md index 04c3062f..24dbbac3 100644 --- a/src/content/docs/reference/box/cachyos/cachyos-pacstrap-builder.md +++ b/src/content/docs/reference/box/cachyos/cachyos-pacstrap-builder.md @@ -14,4 +14,5 @@ title: "cachyos-pacstrap-builder" This box composes: +- `cachyos-os-skills` - `@github.com/opencharly/layer-pacstrap-builder:v2026.272.0421` diff --git a/src/content/docs/reference/box/cachyos/cachyos-pacstrap.md b/src/content/docs/reference/box/cachyos/cachyos-pacstrap.md index d1e01981..c71e3f4e 100644 --- a/src/content/docs/reference/box/cachyos/cachyos-pacstrap.md +++ b/src/content/docs/reference/box/cachyos/cachyos-pacstrap.md @@ -8,3 +8,10 @@ title: "cachyos-pacstrap" |---|---| | **Repo** | `box/cachyos` | | **Builder** | `builder:pacstrap` | + + +## Composition + +This box composes: + +- `cachyos-os-skills` diff --git a/src/content/docs/reference/box/cachyos/cachyos.md b/src/content/docs/reference/box/cachyos/cachyos.md index 8491594b..9c55c2b9 100644 --- a/src/content/docs/reference/box/cachyos/cachyos.md +++ b/src/content/docs/reference/box/cachyos/cachyos.md @@ -7,11 +7,12 @@ title: "cachyos" | | | |---|---| | **Repo** | `box/cachyos` | -| **Base** | `docker.io/cachyos/cachyos-v3@sha256:2f87e702822dc3bc1c527215ace3f7b1b20c5d9d4171bb78e012557be477d487` | +| **Base** | `docker.io/cachyos/cachyos-v3@sha256:f50fa29540b3de01845f908202c91e4cddc7d1cdaac1b25ad33332afba94184b` | ## Composition This box composes: +- `cachyos-os-skills` - `cachyos-base-check` diff --git a/src/content/docs/reference/box/cachyos/comfyui.md b/src/content/docs/reference/box/cachyos/comfyui.md index dc6b835a..8992b0c1 100644 --- a/src/content/docs/reference/box/cachyos/comfyui.md +++ b/src/content/docs/reference/box/cachyos/comfyui.md @@ -15,5 +15,5 @@ title: "comfyui" This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` -- `@github.com/opencharly/pod-comfyui:v2026.274.0700` +- `@github.com/opencharly/pod-comfyui:v2026.290.1729` - `@github.com/opencharly/pod-dbus:v2026.274.0648` diff --git a/src/content/docs/reference/box/cachyos/crabbox-e2e.md b/src/content/docs/reference/box/cachyos/crabbox-e2e.md index 304ee623..107e1b60 100644 --- a/src/content/docs/reference/box/cachyos/crabbox-e2e.md +++ b/src/content/docs/reference/box/cachyos/crabbox-e2e.md @@ -15,8 +15,8 @@ title: "crabbox-e2e" This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` -- `@github.com/opencharly/layer-crabbox:v2026.274.0609` -- `@github.com/opencharly/plugin-crabbox/candy/plugin-crabbox:v2026.272.0026` -- `@github.com/opencharly/pod-crabbox:v2026.274.0652` -- `@github.com/opencharly/layer-container-nesting:v2026.271.2309` +- `@github.com/opencharly/layer-crabbox:v2026.293.1001` +- `@github.com/opencharly/plugin-crabbox/candy/plugin-crabbox:v2026.293.1011` +- `@github.com/opencharly/pod-crabbox-coordinator:v2026.293.1003` +- `@github.com/opencharly/layer-container-nesting:v2026.293.1724` - `crabbox-nesting-dns` diff --git a/src/content/docs/reference/box/cachyos/crabbox.md b/src/content/docs/reference/box/cachyos/crabbox.md index 34572bc0..32bc109e 100644 --- a/src/content/docs/reference/box/cachyos/crabbox.md +++ b/src/content/docs/reference/box/cachyos/crabbox.md @@ -15,5 +15,5 @@ title: "crabbox" This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` -- `@github.com/opencharly/layer-crabbox:v2026.274.0609` -- `@github.com/opencharly/plugin-crabbox/candy/plugin-crabbox:v2026.272.0026` +- `@github.com/opencharly/layer-crabbox:v2026.293.1001` +- `@github.com/opencharly/plugin-crabbox/candy/plugin-crabbox:v2026.293.1011` diff --git a/src/content/docs/reference/box/cachyos/githubrunner.md b/src/content/docs/reference/box/cachyos/githubrunner.md index 73050344..8ca11f1a 100644 --- a/src/content/docs/reference/box/cachyos/githubrunner.md +++ b/src/content/docs/reference/box/cachyos/githubrunner.md @@ -14,9 +14,10 @@ title: "githubrunner" This box composes: +- `cachyos-os-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/pod-github-runner:v2026.279.0028` -- `@github.com/opencharly/layer-charly:v2026.274.0345` +- `@github.com/opencharly/layer-charly:v2026.281.2113` - `@github.com/opencharly/layer-gh:v2026.272.0136` - `@github.com/opencharly/pod-dbus:v2026.274.0648` - `@github.com/opencharly/layer-container-nesting:v2026.271.2309` diff --git a/src/content/docs/reference/box/cachyos/immich-ml.md b/src/content/docs/reference/box/cachyos/immich-ml.md index 6db50219..48fff46e 100644 --- a/src/content/docs/reference/box/cachyos/immich-ml.md +++ b/src/content/docs/reference/box/cachyos/immich-ml.md @@ -16,7 +16,7 @@ This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/layer-nodejs:v2026.272.0322` -- `@github.com/opencharly/layer-python-ml:v2026.274.0754` +- `@github.com/opencharly/layer-python-ml:v2026.290.1914` - `@github.com/opencharly/layer-supervisord:v2026.271.1817` - `@github.com/opencharly/pod-postgresql:v2026.272.0233` - `@github.com/opencharly/layer-vectorchord:v2026.273.1836` diff --git a/src/content/docs/reference/box/cachyos/jupyter-ml.md b/src/content/docs/reference/box/cachyos/jupyter-ml.md index 9d88e1b0..d177359e 100644 --- a/src/content/docs/reference/box/cachyos/jupyter-ml.md +++ b/src/content/docs/reference/box/cachyos/jupyter-ml.md @@ -15,6 +15,6 @@ title: "jupyter-ml" This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` -- `@github.com/opencharly/pod-jupyter-ml:v2026.274.0802` +- `@github.com/opencharly/pod-jupyter-ml:v2026.290.1836` - `@github.com/opencharly/layer-notebook-templates:v2026.272.0457` - `@github.com/opencharly/pod-dbus:v2026.274.0648` diff --git a/src/content/docs/reference/box/cachyos/nvidia.md b/src/content/docs/reference/box/cachyos/nvidia.md index 79e0bb0f..e4934041 100644 --- a/src/content/docs/reference/box/cachyos/nvidia.md +++ b/src/content/docs/reference/box/cachyos/nvidia.md @@ -15,5 +15,5 @@ title: "nvidia" This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` -- `@github.com/opencharly/layer-nvidia:v2026.271.1817` -- `@github.com/opencharly/layer-cuda:v2026.274.0643` +- `@github.com/opencharly/layer-nvidia:7766a9d06ec5fe8c276c091a68fb72cea12688e3` +- `@github.com/opencharly/layer-cuda:v2026.290.2052` diff --git a/src/content/docs/reference/box/cachyos/openwebui.md b/src/content/docs/reference/box/cachyos/openwebui.md new file mode 100644 index 00000000..af36108d --- /dev/null +++ b/src/content/docs/reference/box/cachyos/openwebui.md @@ -0,0 +1,27 @@ +--- +title: "openwebui" +description: "Open Web UI — the LLM chat front-end — on the CachyOS (x86_64_v3) base, with its auto-configuring entrypoint and the open-webui 0.12.3 release from PyPI through pixi." +--- + + + +| | | +|---|---| +| **Repo** | `box/cachyos` | +| **Base** | `cachyos` | + +Open Web UI — the LLM chat front-end — on the CachyOS (x86_64_v3) base, +with its auto-configuring entrypoint and the open-webui 0.12.3 release +from PyPI through pixi. Composes agent-forwarding (GPG/SSH/direnv for the +forwarded-agent workflow) and pod-dbus, the same three candies the Fedora +box uses, so the two images differ only by base distro. The service is +supervisord-managed on port 8080 and reaches LLM providers through the +entrypoint's env/secrets projection. + +## Composition + +This box composes: + +- `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` +- `@github.com/opencharly/pod-openwebui:v2026.293.1944` +- `@github.com/opencharly/pod-dbus:v2026.274.0648` diff --git a/src/content/docs/reference/box/cachyos/python-ml.md b/src/content/docs/reference/box/cachyos/python-ml.md index dcc88b3d..b15f8c43 100644 --- a/src/content/docs/reference/box/cachyos/python-ml.md +++ b/src/content/docs/reference/box/cachyos/python-ml.md @@ -15,4 +15,4 @@ title: "python-ml" This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` -- `@github.com/opencharly/layer-python-ml:v2026.274.0754` +- `@github.com/opencharly/layer-python-ml:v2026.290.1914` diff --git a/src/content/docs/reference/box/cachyos/selkies-kde-nvidia.md b/src/content/docs/reference/box/cachyos/selkies-kde-nvidia.md index 80a35060..43b640d5 100644 --- a/src/content/docs/reference/box/cachyos/selkies-kde-nvidia.md +++ b/src/content/docs/reference/box/cachyos/selkies-kde-nvidia.md @@ -14,6 +14,7 @@ title: "selkies-kde-nvidia" This box composes: +- `cachyos-selkies-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/layer-selkies-kde-desktop:v2026.274.1343` - `@github.com/opencharly/pod-dbus:v2026.274.0648` diff --git a/src/content/docs/reference/box/cachyos/selkies-kde.md b/src/content/docs/reference/box/cachyos/selkies-kde.md index 1de9814d..e0d6db89 100644 --- a/src/content/docs/reference/box/cachyos/selkies-kde.md +++ b/src/content/docs/reference/box/cachyos/selkies-kde.md @@ -14,6 +14,7 @@ title: "selkies-kde" This box composes: +- `cachyos-selkies-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/layer-selkies-kde-desktop:v2026.274.1343` - `@github.com/opencharly/pod-dbus:v2026.274.0648` diff --git a/src/content/docs/reference/box/cachyos/selkies-labwc-nvidia.md b/src/content/docs/reference/box/cachyos/selkies-labwc-nvidia.md index 6643cf50..678ac7ba 100644 --- a/src/content/docs/reference/box/cachyos/selkies-labwc-nvidia.md +++ b/src/content/docs/reference/box/cachyos/selkies-labwc-nvidia.md @@ -14,6 +14,7 @@ title: "selkies-labwc-nvidia" This box composes: +- `cachyos-selkies-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/pod-selkies-desktop:v2026.274.1323` - `@github.com/opencharly/pod-dbus:v2026.274.0648` diff --git a/src/content/docs/reference/box/cachyos/selkies-labwc.md b/src/content/docs/reference/box/cachyos/selkies-labwc.md index 2be60a53..216ca142 100644 --- a/src/content/docs/reference/box/cachyos/selkies-labwc.md +++ b/src/content/docs/reference/box/cachyos/selkies-labwc.md @@ -14,6 +14,7 @@ title: "selkies-labwc" This box composes: +- `cachyos-selkies-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/pod-selkies-desktop:v2026.274.1323` - `@github.com/opencharly/pod-dbus:v2026.274.0648` diff --git a/src/content/docs/reference/box/cachyos/unsloth-studio.md b/src/content/docs/reference/box/cachyos/unsloth-studio.md index 2f3fb9f1..f02cad36 100644 --- a/src/content/docs/reference/box/cachyos/unsloth-studio.md +++ b/src/content/docs/reference/box/cachyos/unsloth-studio.md @@ -15,6 +15,6 @@ title: "unsloth-studio" This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` -- `@github.com/opencharly/pod-unsloth-studio:v2026.274.0809` +- `@github.com/opencharly/pod-unsloth-studio:v2026.290.1913` - `@github.com/opencharly/layer-notebook-finetuning:v2026.272.0321` - `@github.com/opencharly/pod-dbus:v2026.274.0648` diff --git a/src/content/docs/reference/box/cachyos/versa.md b/src/content/docs/reference/box/cachyos/versa.md index 77abbedb..50379204 100644 --- a/src/content/docs/reference/box/cachyos/versa.md +++ b/src/content/docs/reference/box/cachyos/versa.md @@ -14,11 +14,12 @@ title: "versa" This box composes: +- `cachyos-app-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` -- `@github.com/opencharly/layer-nvidia:v2026.271.1817` -- `@github.com/opencharly/layer-cuda:v2026.274.0643` -- `@github.com/opencharly/pod-marimo:v2026.274.0753` -- `@github.com/opencharly/pod-airflow:v2026.274.1033` +- `@github.com/opencharly/layer-nvidia:7766a9d06ec5fe8c276c091a68fb72cea12688e3` +- `@github.com/opencharly/layer-cuda:v2026.290.2052` +- `@github.com/opencharly/pod-marimo:v2026.290.2104` +- `@github.com/opencharly/pod-airflow:v2026.290.2110` - `@github.com/opencharly/pod-osm-tools:v2026.274.0631` - `@github.com/opencharly/pod-maputnik:v2026.274.0617` - `@github.com/opencharly/pod-pmtiles-viewer:v2026.274.0620` diff --git a/src/content/docs/reference/box/debian/debian-builder.md b/src/content/docs/reference/box/debian/debian-builder.md index 12102ead..d96acbdf 100644 --- a/src/content/docs/reference/box/debian/debian-builder.md +++ b/src/content/docs/reference/box/debian/debian-builder.md @@ -17,3 +17,4 @@ This box composes: - `@github.com/opencharly/layer-pixi:v2026.272.0440` - `@github.com/opencharly/layer-nodejs:v2026.272.0322` - `@github.com/opencharly/layer-build-toolchain:v2026.271.1840` +- `debian-skills` diff --git a/src/content/docs/reference/box/debian/debian-coder.md b/src/content/docs/reference/box/debian/debian-coder.md index 2b3acfa1..d7444dd3 100644 --- a/src/content/docs/reference/box/debian/debian-coder.md +++ b/src/content/docs/reference/box/debian/debian-coder.md @@ -40,3 +40,4 @@ This box composes: - `@github.com/opencharly/layer-github-actions:v2026.272.0135` - `@github.com/opencharly/layer-google-cloud-npm:v2026.273.1835` - `@github.com/opencharly/layer-grafana-tools:v2026.272.0139` +- `debian-skills` diff --git a/src/content/docs/reference/box/debian/debian-debootstrap-builder.md b/src/content/docs/reference/box/debian/debian-debootstrap-builder.md index 6139ee27..6cf33bc9 100644 --- a/src/content/docs/reference/box/debian/debian-debootstrap-builder.md +++ b/src/content/docs/reference/box/debian/debian-debootstrap-builder.md @@ -15,3 +15,4 @@ title: "debian-debootstrap-builder" This box composes: - `@github.com/opencharly/layer-debootstrap-builder:v2026.272.0019` +- `debian-skills` diff --git a/src/content/docs/reference/box/debian/debian-debootstrap.md b/src/content/docs/reference/box/debian/debian-debootstrap.md index e08644f2..f9429b9c 100644 --- a/src/content/docs/reference/box/debian/debian-debootstrap.md +++ b/src/content/docs/reference/box/debian/debian-debootstrap.md @@ -8,3 +8,10 @@ title: "debian-debootstrap" |---|---| | **Repo** | `box/debian` | | **Builder** | `builder:debootstrap` | + + +## Composition + +This box composes: + +- `debian-skills` diff --git a/src/content/docs/reference/box/debian/debian.md b/src/content/docs/reference/box/debian/debian.md index fc8f7944..5b7a11ad 100644 --- a/src/content/docs/reference/box/debian/debian.md +++ b/src/content/docs/reference/box/debian/debian.md @@ -8,3 +8,10 @@ title: "debian" |---|---| | **Repo** | `box/debian` | | **Base** | `debian:13` | + + +## Composition + +This box composes: + +- `debian-skills` diff --git a/src/content/docs/reference/box/fedora/charly-fedora.md b/src/content/docs/reference/box/fedora/charly-fedora.md index a8566a0f..fdac66a4 100644 --- a/src/content/docs/reference/box/fedora/charly-fedora.md +++ b/src/content/docs/reference/box/fedora/charly-fedora.md @@ -14,6 +14,7 @@ title: "charly-fedora" This box composes: +- `fedora-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/layer-supervisord:v2026.271.1817` - `@github.com/opencharly/layer-charly:v2026.274.0345` @@ -21,4 +22,4 @@ This box composes: - `@github.com/opencharly/layer-gh:v2026.272.0136` - `@github.com/opencharly/pod-sshd:v2026.272.0324` - `@github.com/opencharly/layer-container-nesting:v2026.271.2309` -- `@github.com/opencharly/layer-nvidia:v2026.271.1817` +- `@github.com/opencharly/layer-nvidia:054aa7702ebe79e8be444764f91a03933ba45eec` diff --git a/src/content/docs/reference/box/fedora/fedora-builder.md b/src/content/docs/reference/box/fedora/fedora-builder.md index 2584f926..3eb44600 100644 --- a/src/content/docs/reference/box/fedora/fedora-builder.md +++ b/src/content/docs/reference/box/fedora/fedora-builder.md @@ -14,6 +14,7 @@ title: "fedora-builder" This box composes: +- `fedora-skills` - `@github.com/opencharly/layer-pixi:v2026.272.0440` - `@github.com/opencharly/layer-nodejs:v2026.272.0322` - `@github.com/opencharly/layer-build-toolchain:v2026.271.1840` diff --git a/src/content/docs/reference/box/fedora/fedora-coder.md b/src/content/docs/reference/box/fedora/fedora-coder.md index 863e4035..72d4bbe6 100644 --- a/src/content/docs/reference/box/fedora/fedora-coder.md +++ b/src/content/docs/reference/box/fedora/fedora-coder.md @@ -14,6 +14,7 @@ title: "fedora-coder" This box composes: +- `fedora-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/pod-sshd:v2026.272.0324` - `@github.com/opencharly/pod-charly-mcp:v2026.274.0406` diff --git a/src/content/docs/reference/box/fedora/fedora-nonfree.md b/src/content/docs/reference/box/fedora/fedora-nonfree.md index dbe44c8b..6e19b050 100644 --- a/src/content/docs/reference/box/fedora/fedora-nonfree.md +++ b/src/content/docs/reference/box/fedora/fedora-nonfree.md @@ -14,4 +14,5 @@ title: "fedora-nonfree" This box composes: +- `fedora-skills` - `@github.com/opencharly/layer-rpmfusion:v2026.272.0429` diff --git a/src/content/docs/reference/box/fedora/fedora-test.md b/src/content/docs/reference/box/fedora/fedora-test.md index b9302caa..c22f4171 100644 --- a/src/content/docs/reference/box/fedora/fedora-test.md +++ b/src/content/docs/reference/box/fedora/fedora-test.md @@ -14,6 +14,7 @@ title: "fedora-test" This box composes: +- `fedora-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/pod-traefik:v2026.274.0627` - `@github.com/opencharly/pod-testapi:v2026.274.0637` diff --git a/src/content/docs/reference/box/fedora/fedora.md b/src/content/docs/reference/box/fedora/fedora.md index 235037af..fe588cf3 100644 --- a/src/content/docs/reference/box/fedora/fedora.md +++ b/src/content/docs/reference/box/fedora/fedora.md @@ -8,3 +8,10 @@ title: "fedora" |---|---| | **Repo** | `box/fedora` | | **Base** | `quay.io/fedora/fedora:43` | + + +## Composition + +This box composes: + +- `fedora-skills` diff --git a/src/content/docs/reference/box/fedora/immich-ml.md b/src/content/docs/reference/box/fedora/immich-ml.md index 2611e854..32ab845a 100644 --- a/src/content/docs/reference/box/fedora/immich-ml.md +++ b/src/content/docs/reference/box/fedora/immich-ml.md @@ -16,8 +16,8 @@ This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/layer-nodejs:v2026.272.0322` -- `@github.com/opencharly/layer-cuda:v2026.274.0643` -- `@github.com/opencharly/layer-python-ml:v2026.274.0754` +- `@github.com/opencharly/layer-cuda:v2026.290.1513` +- `@github.com/opencharly/layer-python-ml:v2026.290.1914` - `@github.com/opencharly/layer-supervisord:v2026.271.1817` - `@github.com/opencharly/layer-vectorchord:v2026.273.1836` - `@github.com/opencharly/pod-redis:v2026.272.0226` diff --git a/src/content/docs/reference/box/fedora/jupyter-ml-notebook.md b/src/content/docs/reference/box/fedora/jupyter-ml-notebook.md index 51b25e77..94a7c509 100644 --- a/src/content/docs/reference/box/fedora/jupyter-ml-notebook.md +++ b/src/content/docs/reference/box/fedora/jupyter-ml-notebook.md @@ -14,6 +14,7 @@ title: "jupyter-ml-notebook" This box composes: +- `fedora-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/pod-jupyter-ml:v2026.274.0802` - `@github.com/opencharly/layer-notebook-templates:v2026.272.0457` diff --git a/src/content/docs/reference/box/fedora/nvidia.md b/src/content/docs/reference/box/fedora/nvidia.md index 20c1df76..1e777110 100644 --- a/src/content/docs/reference/box/fedora/nvidia.md +++ b/src/content/docs/reference/box/fedora/nvidia.md @@ -15,5 +15,5 @@ title: "nvidia" This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` -- `@github.com/opencharly/layer-nvidia:v2026.271.1817` -- `@github.com/opencharly/layer-cuda:v2026.274.0643` +- `@github.com/opencharly/layer-nvidia:054aa7702ebe79e8be444764f91a03933ba45eec` +- `@github.com/opencharly/layer-cuda:v2026.290.1513` diff --git a/src/content/docs/reference/box/fedora/openwebui.md b/src/content/docs/reference/box/fedora/openwebui.md index 270e245f..a2b0c227 100644 --- a/src/content/docs/reference/box/fedora/openwebui.md +++ b/src/content/docs/reference/box/fedora/openwebui.md @@ -15,5 +15,5 @@ title: "openwebui" This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` -- `@github.com/opencharly/pod-openwebui:v2026.274.0629` +- `@github.com/opencharly/pod-openwebui:v2026.293.1944` - `@github.com/opencharly/pod-dbus:v2026.274.0648` diff --git a/src/content/docs/reference/box/fedora/python-ml.md b/src/content/docs/reference/box/fedora/python-ml.md index 50b0e554..6d3a44f9 100644 --- a/src/content/docs/reference/box/fedora/python-ml.md +++ b/src/content/docs/reference/box/fedora/python-ml.md @@ -15,4 +15,4 @@ title: "python-ml" This box composes: - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` -- `@github.com/opencharly/layer-python-ml:v2026.274.0754` +- `@github.com/opencharly/layer-python-ml:v2026.290.1914` diff --git a/src/content/docs/reference/box/fedora/sway-browser-vnc.md b/src/content/docs/reference/box/fedora/sway-browser-vnc.md index 3bf6ef2c..1b96e2b9 100644 --- a/src/content/docs/reference/box/fedora/sway-browser-vnc.md +++ b/src/content/docs/reference/box/fedora/sway-browser-vnc.md @@ -14,5 +14,6 @@ title: "sway-browser-vnc" This box composes: +- `fedora-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/layer-sway-desktop-vnc:v2026.274.1428` diff --git a/src/content/docs/reference/box/fedora/tutorial-shell.md b/src/content/docs/reference/box/fedora/tutorial-shell.md index 4204f737..93cde530 100644 --- a/src/content/docs/reference/box/fedora/tutorial-shell.md +++ b/src/content/docs/reference/box/fedora/tutorial-shell.md @@ -31,6 +31,7 @@ plans running against this same image, so the box does not restate it. This box composes: +- `fedora-skills` - `@github.com/opencharly/layer-supervisord:v2026.271.1817` - `@github.com/opencharly/layer-ripgrep:v2026.235.1653` - `@github.com/opencharly/pod-sshd:v2026.272.0324` diff --git a/src/content/docs/reference/box/fedora/valkey-test.md b/src/content/docs/reference/box/fedora/valkey-test.md index 1a1b0c61..4d8e586f 100644 --- a/src/content/docs/reference/box/fedora/valkey-test.md +++ b/src/content/docs/reference/box/fedora/valkey-test.md @@ -14,6 +14,7 @@ title: "valkey-test" This box composes: +- `fedora-skills` - `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` - `@github.com/opencharly/layer-supervisord:v2026.271.1817` - `@github.com/opencharly/pod-valkey:v2026.272.0326` diff --git a/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-builder.md b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-builder.md new file mode 100644 index 00000000..97aeb0b8 --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-builder.md @@ -0,0 +1,20 @@ +--- +title: "arch-builder" +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | +| **Base** | `arch` | + + +## Composition + +This box composes: + +- `@github.com/opencharly/layer-pixi:v2026.272.0440` +- `@github.com/opencharly/layer-nodejs:v2026.272.0322` +- `@github.com/opencharly/layer-build-toolchain:v2026.271.1840` +- `@github.com/opencharly/layer-yay:v2026.272.0425` diff --git a/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-coder.md b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-coder.md new file mode 100644 index 00000000..997afe1a --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-coder.md @@ -0,0 +1,42 @@ +--- +title: "arch-coder" +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | +| **Base** | `arch` | + + +## Composition + +This box composes: + +- `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` +- `@github.com/opencharly/pod-sshd:v2026.272.0324` +- `@github.com/opencharly/pod-charly-mcp:v2026.274.0406` +- `@github.com/opencharly/layer-container-nesting:v2026.271.2309` +- `@github.com/opencharly/pod-dbus:v2026.274.0648` +- `@github.com/opencharly/layer-tmux:v2026.272.0425` +- `@github.com/opencharly/layer-language-runtimes:v2026.273.1816` +- `@github.com/opencharly/layer-golang:v2026.272.0137` +- `@github.com/opencharly/layer-pixi:v2026.272.0440` +- `@github.com/opencharly/layer-uv:v2026.272.0409` +- `@github.com/opencharly/layer-build-toolchain:v2026.271.1840` +- `@github.com/opencharly/layer-dev-tools:v2026.272.0100` +- `@github.com/opencharly/layer-pre-commit:v2026.274.0641` +- `@github.com/opencharly/layer-gh:v2026.272.0136` +- `@github.com/opencharly/layer-typst:v2026.272.0407` +- `@github.com/opencharly/layer-asciinema:v2026.273.1825` +- `@github.com/opencharly/layer-claude-code:v2026.271.2310` +- `@github.com/opencharly/layer-codex:v2026.274.0634` +- `@github.com/opencharly/layer-forgecode:v2026.274.0635` +- `@github.com/opencharly/layer-oracle:v2026.274.0649` +- `@github.com/opencharly/layer-devops-tools:v2026.274.0631` +- `@github.com/opencharly/layer-kubernetes:v2026.272.0319` +- `@github.com/opencharly/layer-docker-ce:v2026.272.0100` +- `@github.com/opencharly/layer-github-actions:v2026.272.0135` +- `@github.com/opencharly/layer-google-cloud-npm:v2026.273.1835` +- `@github.com/opencharly/layer-grafana-tools:v2026.272.0139` diff --git a/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-pacstrap-builder.md b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-pacstrap-builder.md new file mode 100644 index 00000000..54e7b3a2 --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-pacstrap-builder.md @@ -0,0 +1,17 @@ +--- +title: "arch-pacstrap-builder" +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | +| **Base** | `arch` | + + +## Composition + +This box composes: + +- `@github.com/opencharly/layer-pacstrap-builder:v2026.272.0421` diff --git a/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-pacstrap.md b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-pacstrap.md new file mode 100644 index 00000000..fc67c020 --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-pacstrap.md @@ -0,0 +1,10 @@ +--- +title: "arch-pacstrap" +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | +| **Builder** | `builder:pacstrap` | diff --git a/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-test.md b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-test.md new file mode 100644 index 00000000..272ae24e --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch-test.md @@ -0,0 +1,19 @@ +--- +title: "arch-test" +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | +| **Base** | `arch` | + + +## Composition + +This box composes: + +- `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` +- `arch-pac-test` +- `arch-aur-test` diff --git a/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch.md b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch.md new file mode 100644 index 00000000..c3ae0131 --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/arch.md @@ -0,0 +1,10 @@ +--- +title: "arch" +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | +| **Base** | `quay.io/archlinux/archlinux:base-20260719.0.558306` | diff --git a/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/charly-arch.md b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/charly-arch.md new file mode 100644 index 00000000..41372cc5 --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/charly-arch.md @@ -0,0 +1,23 @@ +--- +title: "charly-arch" +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | +| **Base** | `arch` | + + +## Composition + +This box composes: + +- `@github.com/opencharly/layer-agent-forwarding:v2026.274.0608` +- `@github.com/opencharly/pod-charly-mcp:v2026.274.0406` +- `@github.com/opencharly/layer-golang:v2026.272.0137` +- `@github.com/opencharly/layer-gh:v2026.272.0136` +- `@github.com/opencharly/pod-sshd:v2026.272.0324` +- `@github.com/opencharly/layer-container-nesting:v2026.271.2309` +- `@github.com/opencharly/layer-nvidia:v2026.289.1705` diff --git a/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/check-agent-box.md b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/check-agent-box.md new file mode 100644 index 00000000..f7085810 --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/check-agent-box.md @@ -0,0 +1,28 @@ +--- +title: "check-agent-box" +description: "Disposable support image for the complete agent-control R10 bed." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | +| **Base** | `arch` | + +Disposable support image for the complete agent-control R10 bed. It contains the pinned native Pi SDK runtime and Pi-TUI, Claude Code, tmux control mode, and an OpenSSH endpoint. The worktree Charly package supplies the CUE-generated provider channel, agent control plugin, Pi provider, tmux provider, MCP reflection, and generic deployment process transport; no permanent agent service is baked. + +## Composition + +This box composes: + +- `@github.com/opencharly/layer-gh:v2026.272.0136` +- `@github.com/opencharly/layer-charly:v2026.274.0345` +- `@github.com/opencharly/plugin-agent/candy/plugin-agent:v2026.271.2242` +- `@github.com/opencharly/plugin-agent-pi/candy/plugin-agent-pi:v2026.274.0808` +- `@github.com/opencharly/plugin-tmux/candy/plugin-tmux:v2026.272.0422` +- `@github.com/opencharly/layer-supervisord:v2026.271.1817` +- `@github.com/opencharly/layer-tmux:v2026.272.0425` +- `@github.com/opencharly/pod-sshd:v2026.272.0324` +- `@github.com/opencharly/layer-pi-agent:v2026.274.0613` +- `@github.com/opencharly/layer-claude-code:v2026.271.2310` diff --git a/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/check-tmux-box.md b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/check-tmux-box.md new file mode 100644 index 00000000..09ceea86 --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/check-tmux-box.md @@ -0,0 +1,21 @@ +--- +title: "check-tmux-box" +description: "Disposable support image for the typed terminal:tmux R10 bed." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | +| **Base** | `arch` | + +Disposable support image for the typed terminal:tmux R10 bed. It intentionally contains tmux and OpenSSH but no Charly package: deployment and SSH transports must probe the venue and replicate the active worktree binary through EnsureCharlyInDeployVenue before starting the gRPC stdio endpoint. This proves direct and recursively nested routes can control an accessible box without requiring Charly to be preinstalled. It is deliberately a test image, not a product image. + +## Composition + +This box composes: + +- `@github.com/opencharly/layer-supervisord:v2026.271.1817` +- `@github.com/opencharly/layer-tmux:v2026.272.0425` +- `@github.com/opencharly/pod-sshd:v2026.272.0324` diff --git a/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/cuda-arch-builder.md b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/cuda-arch-builder.md new file mode 100644 index 00000000..079c4f76 --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/cuda-arch-builder.md @@ -0,0 +1,18 @@ +--- +title: "cuda-arch-builder" +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | +| **Base** | `arch-builder` | + + +## Composition + +This box composes: + +- `@github.com/opencharly/layer-cuda:v2026.290.1513` +- `@github.com/opencharly/layer-nvenc-headers:v2026.272.0603` diff --git a/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/vscode-test.md b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/vscode-test.md new file mode 100644 index 00000000..ba8a33c0 --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-distro-arch-v2026-290-1914/vscode-test.md @@ -0,0 +1,20 @@ +--- +title: "vscode-test" +description: "Arch vscode install smoke (direct-download path) — backs the check-vscode-pod bed" +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | +| **Base** | `arch` | + +Arch vscode install smoke (direct-download path) — backs the check-vscode-pod bed + +## Composition + +This box composes: + +- `@github.com/opencharly/pod-check-keepalive:v2026.274.0621` +- `@github.com/opencharly/layer-vscode:v2026.272.0410` diff --git a/src/content/docs/reference/box/github-com-opencharly-layer-nvidia-7766a9d06ec5fe8c276c091a68fb72cea12688e3/nvidia-probe.md b/src/content/docs/reference/box/github-com-opencharly-layer-nvidia-7766a9d06ec5fe8c276c091a68fb72cea12688e3/nvidia-probe.md new file mode 100644 index 00000000..d5bf36b9 --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-layer-nvidia-7766a9d06ec5fe8c276c091a68fb72cea12688e3/nvidia-probe.md @@ -0,0 +1,19 @@ +--- +title: "nvidia-probe" +description: "Arch-family box for the nvidia candy check plan." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-nvidia:7766a9d06ec5fe8c276c091a68fb72cea12688e3` | +| **Base** | `arch.arch` | + +Arch-family box for the nvidia candy check plan. The arch base has no dnf, so the nvidia-container-toolkit gpgcheck probe must skip honestly rather than fail -- which is what charly check box nvidia-probe evaluates on the built image. + +## Composition + +This box composes: + +- `nvidia` diff --git a/src/content/docs/reference/box/github-com-opencharly-plugin-crabbox-v2026-293-1011/check-crabbox-pod-image.md b/src/content/docs/reference/box/github-com-opencharly-plugin-crabbox-v2026-293-1011/check-crabbox-pod-image.md new file mode 100644 index 00000000..2f3d7554 --- /dev/null +++ b/src/content/docs/reference/box/github-com-opencharly-plugin-crabbox-v2026-293-1011/check-crabbox-pod-image.md @@ -0,0 +1,20 @@ +--- +title: "check-crabbox-pod-image" +description: "The crabbox verb's own environment — the pinned Crabbox CLI and the plugin under review." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/plugin-crabbox:v2026.293.1011` | +| **Base** | `quay.io/fedora/fedora:43` | + +The crabbox verb's own environment — the pinned Crabbox CLI and the plugin under review. + +## Composition + +This box composes: + +- `@github.com/opencharly/layer-crabbox:v2026.293.1001` +- `plugin-crabbox` diff --git a/src/content/docs/reference/box/omarchy/omarchy-cstream.md b/src/content/docs/reference/box/omarchy/omarchy-cstream.md index 67b88ea2..8801e7df 100644 --- a/src/content/docs/reference/box/omarchy/omarchy-cstream.md +++ b/src/content/docs/reference/box/omarchy/omarchy-cstream.md @@ -60,3 +60,4 @@ This box composes: - `@github.com/opencharly/layer-omarchy-terminal/candy/omarchy-terminal:v2026.274.0623` - `@github.com/opencharly/layer-omarchy-themes/candy/omarchy-themes:v2026.274.0625` - `@github.com/opencharly/layer-omarchy-fonts/candy/omarchy-fonts:v2026.274.0650` +- `omarchy-skills` diff --git a/src/content/docs/reference/box/omarchy/omarchy.md b/src/content/docs/reference/box/omarchy/omarchy.md index 28d253a0..662354b0 100644 --- a/src/content/docs/reference/box/omarchy/omarchy.md +++ b/src/content/docs/reference/box/omarchy/omarchy.md @@ -26,3 +26,4 @@ effect on an Arch base. This box composes: - `@github.com/opencharly/layer-omarchy-base/candy/omarchy-base:v2026.272.0437` +- `omarchy-skills` diff --git a/src/content/docs/reference/box/ubuntu/clawsweeper-review.md b/src/content/docs/reference/box/ubuntu/clawsweeper-review.md new file mode 100644 index 00000000..ed1e2501 --- /dev/null +++ b/src/content/docs/reference/box/ubuntu/clawsweeper-review.md @@ -0,0 +1,21 @@ +--- +title: "clawsweeper-review" +description: "The ClawSweeper review engine (pinned upstream, Node 24 + pnpm, Codex 0.162.1) on the OpenCharly Ollama Cloud responses endpoint." +--- + + + +| | | +|---|---| +| **Repo** | `box/ubuntu` | +| **Base** | `ubuntu:24.04` | + +The ClawSweeper review engine (pinned upstream, Node 24 + pnpm, Codex 0.162.1) on the +OpenCharly Ollama Cloud responses endpoint. Built for `--local-range`: no token, no +GitHub writes, read-only target tree. + +## Composition + +This box composes: + +- `@github.com/opencharly/layer-clawsweeper/candy/clawsweeper-review:v2026.296.1447` diff --git a/src/content/docs/reference/box/ubuntu/ubuntu-builder.md b/src/content/docs/reference/box/ubuntu/ubuntu-builder.md index 37234c23..919db1aa 100644 --- a/src/content/docs/reference/box/ubuntu/ubuntu-builder.md +++ b/src/content/docs/reference/box/ubuntu/ubuntu-builder.md @@ -17,3 +17,4 @@ This box composes: - `@github.com/opencharly/layer-pixi:v2026.272.0440` - `@github.com/opencharly/layer-nodejs:v2026.272.0322` - `@github.com/opencharly/layer-build-toolchain:v2026.271.1840` +- `ubuntu-skills` diff --git a/src/content/docs/reference/box/ubuntu/ubuntu-coder.md b/src/content/docs/reference/box/ubuntu/ubuntu-coder.md index 1b175b33..476f049c 100644 --- a/src/content/docs/reference/box/ubuntu/ubuntu-coder.md +++ b/src/content/docs/reference/box/ubuntu/ubuntu-coder.md @@ -40,3 +40,4 @@ This box composes: - `@github.com/opencharly/layer-github-actions:v2026.272.0135` - `@github.com/opencharly/layer-google-cloud-npm:v2026.273.1835` - `@github.com/opencharly/layer-grafana-tools:v2026.272.0139` +- `ubuntu-skills` diff --git a/src/content/docs/reference/box/ubuntu/ubuntu-debootstrap-builder.md b/src/content/docs/reference/box/ubuntu/ubuntu-debootstrap-builder.md index cfe646d7..42dfdd61 100644 --- a/src/content/docs/reference/box/ubuntu/ubuntu-debootstrap-builder.md +++ b/src/content/docs/reference/box/ubuntu/ubuntu-debootstrap-builder.md @@ -15,3 +15,4 @@ title: "ubuntu-debootstrap-builder" This box composes: - `@github.com/opencharly/layer-debootstrap-builder:v2026.272.0019` +- `ubuntu-skills` diff --git a/src/content/docs/reference/box/ubuntu/ubuntu-debootstrap.md b/src/content/docs/reference/box/ubuntu/ubuntu-debootstrap.md index 012d873c..87394748 100644 --- a/src/content/docs/reference/box/ubuntu/ubuntu-debootstrap.md +++ b/src/content/docs/reference/box/ubuntu/ubuntu-debootstrap.md @@ -8,3 +8,10 @@ title: "ubuntu-debootstrap" |---|---| | **Repo** | `box/ubuntu` | | **Builder** | `builder:debootstrap` | + + +## Composition + +This box composes: + +- `ubuntu-skills` diff --git a/src/content/docs/reference/box/ubuntu/ubuntu.md b/src/content/docs/reference/box/ubuntu/ubuntu.md index 00705f41..7171fc21 100644 --- a/src/content/docs/reference/box/ubuntu/ubuntu.md +++ b/src/content/docs/reference/box/ubuntu/ubuntu.md @@ -8,3 +8,10 @@ title: "ubuntu" |---|---| | **Repo** | `box/ubuntu` | | **Base** | `ubuntu:24.04` | + + +## Composition + +This box composes: + +- `ubuntu-skills` diff --git a/src/content/docs/reference/candy/arch/arch-skills.md b/src/content/docs/reference/candy/arch/arch-skills.md new file mode 100644 index 00000000..c83d9e96 --- /dev/null +++ b/src/content/docs/reference/candy/arch/arch-skills.md @@ -0,0 +1,29 @@ +--- +title: "arch-skills" +description: "Skill-prose bundle for the Arch image family: owns the `arch`, `arch-builder`, `arch-coder`, `arch-test` and `charly-arch` `skill:` entities (sibling nodes in this file) and carries their bodies under .agents/skills//SKILL.md." +--- + + + +| | | +|---|---| +| **Repo** | `box/arch` | + +Skill-prose bundle for the Arch image family: owns the `arch`, `arch-builder`, +`arch-coder`, `arch-test` and `charly-arch` `skill:` entities (sibling nodes in this +file) and carries their bodies under .agents/skills//SKILL.md. +It exists because a `skill:` node's owner must be a candy, not an image — an image has +no source directory, so an image-owned node's prose is unreadable and the skill is +absent from the ai.opencharly.skill OCI label (opencharly/sdk#434). +Composed into every image that carries one of those skills; installs the tree at the +uid-1000 account's ~/.agents/skills so a harness in the image reads the same prose the +label carries. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | install the skill tree at the uid-1000 account's Agent-Skills location | +| `check` | every skill body this candy carries is installed under the uid-1000 account's ~/.agents/skills | diff --git a/src/content/docs/reference/candy/cachyos/cachyos-app-skills.md b/src/content/docs/reference/candy/cachyos/cachyos-app-skills.md new file mode 100644 index 00000000..05376874 --- /dev/null +++ b/src/content/docs/reference/candy/cachyos/cachyos-app-skills.md @@ -0,0 +1,24 @@ +--- +title: "cachyos-app-skills" +description: "The CachyOS skill carrier for the application-profile skills (`charly-cachyos` the workstation profile, `keepassxc-keyring`, `versa`)." +--- + + + +| | | +|---|---| +| **Repo** | `box/cachyos` | + +The CachyOS skill carrier for the application-profile skills (`charly-cachyos` the workstation profile, `keepassxc-keyring`, `versa`). It ships no install +content — its payload is the skill prose under `.agents/skills/`, read at build +time by the skill collector — and it exists because a skill's `owner:` must name +a candy that rides an image, not the image itself (opencharly/sdk#434). + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | this skill-carrier candy ships no install content | +| `check` | this carrier registers as a candy and ships no install content — its skill bodies are validated at build-config time by `charly box validate`, not inside the image | diff --git a/src/content/docs/reference/candy/cachyos/cachyos-os-skills.md b/src/content/docs/reference/candy/cachyos/cachyos-os-skills.md new file mode 100644 index 00000000..b45547f5 --- /dev/null +++ b/src/content/docs/reference/candy/cachyos/cachyos-os-skills.md @@ -0,0 +1,24 @@ +--- +title: "cachyos-os-skills" +description: "The CachyOS skill carrier for the OS skills (`cachyos`, `cachyos-pacstrap`, `cachyos-pacstrap-builder`, `githubrunner`)." +--- + + + +| | | +|---|---| +| **Repo** | `box/cachyos` | + +The CachyOS skill carrier for the OS skills (`cachyos`, `cachyos-pacstrap`, `cachyos-pacstrap-builder`, `githubrunner`). It ships no install +content — its payload is the skill prose under `.agents/skills/`, read at build +time by the skill collector — and it exists because a skill's `owner:` must name +a candy that rides an image, not the image itself (opencharly/sdk#434). + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | this skill-carrier candy ships no install content | +| `check` | this carrier registers as a candy and ships no install content — its skill bodies are validated at build-config time by `charly box validate`, not inside the image | diff --git a/src/content/docs/reference/candy/cachyos/cachyos-selkies-skills.md b/src/content/docs/reference/candy/cachyos/cachyos-selkies-skills.md new file mode 100644 index 00000000..f16c27a2 --- /dev/null +++ b/src/content/docs/reference/candy/cachyos/cachyos-selkies-skills.md @@ -0,0 +1,24 @@ +--- +title: "cachyos-selkies-skills" +description: "The CachyOS skill carrier for the streaming-desktop skills (the four `selkies-*` boxes)." +--- + + + +| | | +|---|---| +| **Repo** | `box/cachyos` | + +The CachyOS skill carrier for the streaming-desktop skills (the four `selkies-*` boxes). It ships no install +content — its payload is the skill prose under `.agents/skills/`, read at build +time by the skill collector — and it exists because a skill's `owner:` must name +a candy that rides an image, not the image itself (opencharly/sdk#434). + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | this skill-carrier candy ships no install content | +| `check` | this carrier registers as a candy and ships no install content — its skill bodies are validated at build-config time by `charly box validate`, not inside the image | diff --git a/src/content/docs/reference/candy/cachyos/containerd-v4-egress.md b/src/content/docs/reference/candy/cachyos/containerd-v4-egress.md new file mode 100644 index 00000000..b045770d --- /dev/null +++ b/src/content/docs/reference/candy/cachyos/containerd-v4-egress.md @@ -0,0 +1,40 @@ +--- +title: "containerd-v4-egress" +description: "The containerd v4 config egress-validation subject (opencharly/charly#929)." +--- + + + +| | | +|---|---| +| **Repo** | `box/cachyos` | + +The containerd v4 config egress-validation subject (opencharly/charly#929). +Installs containerd + crictl + crun + krun and ships the scratch fixture +project whose config: step carries the CONTAINERD.md section 3.1 version-4 +config with validate: containerd_config. The bed +check-containerd-v4-egress-vm generates the fixture through the REAL +verb:egress validator, installs the exact bytes the validator accepted, and +asserts the running daemon serves the crun/krun runtime handlers and the +overlayfs snapshotter. A plugin-egress without the v4 arm fails the +generate with a version conflict, so the bed is red without the schema. + +## Packages + +Installed on every distro: + +- `containerd` +- `crictl` +- `crun` +- `krun` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | ship the scratch fixture project's project root into the guest home | +| `run` | ship the scratch fixture box that composes the egress-validation candy | +| `run` | ship the scratch fixture candy carrying the canonical v4 config and its egress validation | +| `check` | the scratch fixture project is shipped into the guest home with its egress-validation candy | diff --git a/src/content/docs/reference/candy/debian/debian-skills.md b/src/content/docs/reference/candy/debian/debian-skills.md new file mode 100644 index 00000000..f9331cc9 --- /dev/null +++ b/src/content/docs/reference/candy/debian/debian-skills.md @@ -0,0 +1,29 @@ +--- +title: "debian-skills" +description: "Skill-prose bundle for the debian image family: owns the `debian`, `debian-builder`, `debian-coder`, `debian-debootstrap-builder`, `debian-debootstrap` `skill:` entities (sibling nodes in this file) and carries their bodies under .agents/skills//SKILL.md." +--- + + + +| | | +|---|---| +| **Repo** | `box/debian` | + +Skill-prose bundle for the debian image family: owns the `debian`, `debian-builder`, `debian-coder`, `debian-debootstrap-builder`, `debian-debootstrap` `skill:` +entities (sibling nodes in this file) and carries their bodies under +.agents/skills//SKILL.md. +It exists because a `skill:` node's owner must be a candy, not an image — an image has +no source directory, so an image-owned node's prose is unreadable and the skill is +absent from the ai.opencharly.skill OCI label (opencharly/sdk#434). +Composed into every image that carries one of those skills; installs the tree at the +uid-1000 account's ~/.agents/skills so a harness in the image reads the same prose the +label carries. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | install the skill tree at the uid-1000 account's Agent-Skills location | +| `check` | every skill body this candy carries is installed under the uid-1000 account's ~/.agents/skills | diff --git a/src/content/docs/reference/candy/fedora/fedora-skills.md b/src/content/docs/reference/candy/fedora/fedora-skills.md new file mode 100644 index 00000000..8665a7c8 --- /dev/null +++ b/src/content/docs/reference/candy/fedora/fedora-skills.md @@ -0,0 +1,28 @@ +--- +title: "fedora-skills" +description: "The Fedora skill carrier: the package candy that OWNS the ten `fedora*` skill entities (`fedora`, `fedora-builder`, `fedora-nonfree`, `fedora-coder`, `fedora-test`, `charly-fedora`, `jupyter-ml-notebook`, `sway-browser-vnc`, `tutorial-shell`, `valkey-test`)." +--- + + + +| | | +|---|---| +| **Repo** | `box/fedora` | + +The Fedora skill carrier: the package candy that OWNS the ten `fedora*` skill +entities (`fedora`, `fedora-builder`, `fedora-nonfree`, `fedora-coder`, +`fedora-test`, `charly-fedora`, `jupyter-ml-notebook`, `sway-browser-vnc`, +`tutorial-shell`, `valkey-test`). It ships no install content — its payload is +the skill prose under `.agents/skills/`, read at build time by the skill +collector — and it exists because a skill's `owner:` must name a candy that +rides an image, not the image itself (opencharly/sdk#434). Composed by every +Fedora image that owns one of those skills. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | this skill-carrier candy ships no install content | +| `check` | this carrier registers as a candy and ships no install content — its skill bodies are validated at build-config time by `charly box validate`, not inside the image | diff --git a/src/content/docs/reference/candy/github-com-opencharly-distro-arch-v2026-290-1914/arch-aur-test.md b/src/content/docs/reference/candy/github-com-opencharly-distro-arch-v2026-290-1914/arch-aur-test.md new file mode 100644 index 00000000..64b29717 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-distro-arch-v2026-290-1914/arch-aur-test.md @@ -0,0 +1,26 @@ +--- +title: "arch-aur-test" +description: "AUR build smoke test — installs yay-bin from the AUR Minimal candy that exercises the Arch AUR build path by installing yay-bin (a prebuilt yay package) from the AUR." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | + +AUR build smoke test — installs yay-bin from the AUR +Minimal candy that exercises the Arch AUR build path by installing +yay-bin (a prebuilt yay package) from the AUR. Verifiable: the yay +binary it provides lands at /usr/bin/yay and reports its version. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `check` | the AUR-installed yay binary is present at /usr/bin/yay | +| `check` | yay runs and reports its version | +| `check` | file=/usr/bin/yay | +| `check` | command=/usr/bin/yay --version | diff --git a/src/content/docs/reference/candy/github-com-opencharly-distro-arch-v2026-290-1914/arch-pac-test.md b/src/content/docs/reference/candy/github-com-opencharly-distro-arch-v2026-290-1914/arch-pac-test.md new file mode 100644 index 00000000..d257dcee --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-distro-arch-v2026-290-1914/arch-pac-test.md @@ -0,0 +1,28 @@ +--- +title: "arch-pac-test" +description: "pacman repo install smoke test — installs neovim and ripgrep Minimal candy that exercises the Arch pacman repo install path by installing neovim and ripgrep." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/distro-arch:v2026.290.1914` | + +pacman repo install smoke test — installs neovim and ripgrep +Minimal candy that exercises the Arch pacman repo install path by +installing neovim and ripgrep. Verifiable: both binaries (nvim, rg) +land on PATH and the packages are registered. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `check` | the neovim editor binary is installed at /usr/bin/nvim | +| `check` | the ripgrep binary is installed at /usr/bin/rg | +| `check` | file=/usr/bin/nvim | +| `check` | package=neovim | +| `check` | file=/usr/bin/rg | +| `check` | package=ripgrep | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-charly-v2026-281-2113/charly.md b/src/content/docs/reference/candy/github-com-opencharly-layer-charly-v2026-281-2113/charly.md new file mode 100644 index 00000000..1df7ad7a --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-charly-v2026-281-2113/charly.md @@ -0,0 +1,36 @@ +--- +title: "charly" +description: "The full charly toolchain on a deployment — the on-PATH charly CLI plus its composed VM / encrypted-storage / console-relay stack." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-charly:v2026.281.2113` | + +The full charly toolchain on a deployment — the on-PATH charly CLI plus its composed VM / encrypted-storage / console-relay stack. +Full charly toolchain — the CLI binary + the VM stack (virtualization), +encrypted storage (gocryptfs), and console relay (socat) — composed into +ONE layer that works identically on container/pod, host/local, and +bootc/VM targets via the `virtualization` layer's mixed-entry `service:` +pattern. This is the single canonical `charly` layer: bake it where a +deployment needs a persistent on-`$PATH` charly or the full toolchain inside +(the `charly-mcp` server, the `*-charly` showcases, nested-pod orchestrators). +Images that only need transient in-container `charly` (the dbus delegation +path) need NOT bake it — the host copies `charly` in on demand +(`EnsureCharlyInDeployVenue`; see `/charly-tools:charly`). + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `check` | charly version prints a CalVer build stamp on stdout | +| `check` | the gocryptfs encrypted-storage binary (gocryptfs candy) is installed | +| `check` | the socat console-relay binary (socat candy) is installed | +| `check` | the libvirt virsh client (virtualization candy) is installed | +| `check` | the qemu system emulator (virtualization candy) is installed | +| `check` | charly doctor runs and emits its Summary line | +| `check` | command=command -v charly | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-clawsweeper-v2026-296-1447/clawsweeper-review.md b/src/content/docs/reference/candy/github-com-opencharly-layer-clawsweeper-v2026-296-1447/clawsweeper-review.md new file mode 100644 index 00000000..3ccd57d3 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-clawsweeper-v2026-296-1447/clawsweeper-review.md @@ -0,0 +1,49 @@ +--- +title: "clawsweeper-review" +description: "The ClawSweeper review engine as a runnable artefact: a PINNED upstream checkout, Node 24 + pnpm 12.4.1, the OpenAI Codex CLI (the engine's only runner), a CODEX_HOME configured for the OpenCharly Ollama Cloud endpoint, and an `opencharly` target-profile overlay so any opencharly/ resolves." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-clawsweeper:v2026.296.1447` | + +The ClawSweeper review engine as a runnable artefact: a PINNED upstream checkout, +Node 24 + pnpm 12.4.1, the OpenAI Codex CLI (the engine's only runner), a +CODEX_HOME configured for the OpenCharly Ollama Cloud endpoint, and an +`opencharly` target-profile overlay so any opencharly/ resolves. + +This image is the REVIEW HALF of PR validation. It is run as a disposable +container with the PR tree mounted read-only and NO GitHub token: `--local-range` +reads merge-base(base, HEAD)..HEAD and performs no GitHub writes, so the verdict +leaves the sandbox as JSON and the caller posts it. Codex's sandbox needs +bubblewrap and unprivileged user namespaces; the runner image enables those. + +The engine/endpoint pairing is MEASURED, not assumed: Codex 0.162.1 speaks +stateless Responses to https://ollama.com/v1 and performs real shell tool calls +(probe: `codex exec` ran `uname -s && uname -m`, returned Linux/x86_64). Codex +accepts only `wire_api = "responses"`; Ollama Cloud serves that. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | install the pinned Node runtime from the official tarball | +| `run` | install the pinned pnpm and the pinned Codex CLI | +| `run` | clone the pinned ClawSweeper checkout and build it | +| `run` | add the opencharly target-profile fallback so any opencharly/ resolves | +| `run` | write the Codex home configured for the Ollama Cloud endpoint | +| `run` | install the one-shot review entrypoint | +| `check` | Node 24 reports its version | +| `check` | pnpm reports the pinned version | +| `check` | the Codex CLI reports the pinned version | +| `check` | the built engine loads and resolves an opencharly target through the overlay | +| `check` | the opencharly target fallback is present | +| `check` | the Codex home carries config.toml naming the Ollama Cloud responses endpoint | +| `check` | the entrypoint gives Codex a writable home as the image's own user | +| `check` | the one-shot review entrypoint runs and describes its invocation | +| `run` | pre-install the engine's input scanner into the image user's cache | +| `check` | the input scanner is baked into THIS user's private cache | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-container-nesting-v2026-293-1724/container-nesting.md b/src/content/docs/reference/candy/github-com-opencharly-layer-container-nesting-v2026-293-1724/container-nesting.md new file mode 100644 index 00000000..8e01250e --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-container-nesting-v2026-293-1724/container-nesting.md @@ -0,0 +1,70 @@ +--- +title: "container-nesting" +description: "Rootless nested podman/buildah/skopeo inside a rootless outer container -- zero added capabilities, no --privileged." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-container-nesting:v2026.293.1724` | + +Rootless nested podman/buildah/skopeo inside a rootless outer container -- zero added capabilities, no --privileged. +Ports quay.io/podman/stable's canonical rootless-in-rootless configuration +into the candy system. Installs podman + crun + buildah + skopeo + +fuse-overlayfs, writes containers.conf with every namespace=host (the +userns=host line is what bypasses the kernel mount_too_revealing /proc +check), a two-range subuid layout that fits the keep-id window, +newuidmap/newgidmap file caps, policy.json and storage.conf -- so an inner +`podman run` of a fresh container succeeds with no cap_add and no +--privileged. Every artifact below is observable in the built image; the +end-to-end nested run is provable on a live deployment. + +## Packages + +Installed on every distro: + +- `buildah` +- `fuse-overlayfs` +- `skopeo` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | command=touch /etc/subuid /etc/subgid sed -i "/^root:/d" /etc/subuid /etc/subgid echo "root:1:65535" >> /etc/subuid echo "root:1:65535" >> /etc/subgid uid1000=$(getent passwd 1000 2>/dev/null \| cut -d: -f1 \|\| true) if [ -n "${uid1000}" ] && [ "${uid1000}" != "root" ]; then sed -i "/^${uid1000}:/d" /etc/subuid /etc/subgid { echo "${uid1000}:1:999" echo "${uid1000}:1001:64535" } >> /etc/subuid { echo "${uid1000}:1:999" echo "${uid1000}:1001:64535" } >> /etc/subgid fi | +| `run` | grant cap_setuid/cap_setgid to newuidmap/newgidmap AND strip the setuid-root bit. Debian/Ubuntu's uidmap package ships these binaries setuid-root (mode 4755); a newuidmap that is BOTH setuid-root AND file-capability'd fails inside a nested rootless user namespace with "newuidmap: open of uid_map failed: Permission denied". Fedora/Arch ship them cap-only (no setuid bit), so `chmod u-s` makes every distro match that working posture and is a no-op where the bit is already absent. RDD-confirmed. | +| `run` | mkdir=/etc/containers | +| `run` | mkdir=${HOME}/.config/containers | +| `run` | write=/etc/containers/containers.conf | +| `run` | write=${HOME}/.config/containers/containers.conf | +| `run` | write=/etc/containers/policy.json | +| `run` | write=${HOME}/.config/containers/policy.json | +| `run` | write=/etc/containers/storage.conf | +| `run` | write=${HOME}/.config/containers/storage.conf | +| `check` | the podman container engine is installed for in-container use | +| `check` | the buildah image-build tool is installed | +| `check` | the skopeo image-copy tool is installed | +| `check` | containers.conf pins userns=host so the inner /proc mount is not rejected by the kernel mount_too_revealing check | +| `check` | policy.json is present so podman pull/run accepts an image signature policy | +| `check` | newuidmap carries the cap_setuid file capability so a nested user namespace can be delegated | +| `check` | newuidmap is NOT setuid-root — only the cap_setuid file capability remains; a binary that is BOTH setuid-root (Debian/Ubuntu's uidmap default) AND cap-bearing fails to write uid_map inside a nested rootless user namespace | +| `check` | /etc/subuid declares the username:start:count delegation ranges the inner podman maps from | +| `agent-check` | a fresh rootless `podman run` of an inner container succeeds end-to-end with no added capabilities and no --privileged | +| `check` | command=/usr/bin/podman --version | +| `check` | command=/usr/bin/buildah --version | +| `check` | command=/usr/bin/skopeo --version | +| `check` | file=/usr/bin/newuidmap | +| `check` | file=/usr/bin/newgidmap | +| `check` | file=/usr/bin/tailscale | +| `check` | command=/usr/bin/tailscale version | +| `check` | the uid-1000 user has exactly two subuid delegation ranges (cross-distro — the user is `user` on fedora/arch but `ubuntu`/`debian` under adopt user-policy, so resolve the name via getent rather than hardcoding `user:`) | +| `check` | command=grep -E '^userns\s*=\s*"host"' ${HOME}/.config/containers/containers.conf | +| `check` | command=sh -c 'env \| grep -q "^_CONTAINERS_USERNS_CONFIGURED="' | +| `check` | command=sh -c 'env \| grep -qx "BUILDAH_ISOLATION=chroot"' | +| `run` | mkdir -p /usr/share/charly/nesting-smoke && skopeo copy docker://quay.io/libpod/alpine:latest dir:/usr/share/charly/nesting-smoke | +| `check` | the build-fetched OCI layout is baked into the image | +| `run` | skopeo copy dir:/usr/share/charly/nesting-smoke containers-storage:quay.io/libpod/alpine:latest | +| `check` | command=podman run --rm --pull=never quay.io/libpod/alpine:latest /bin/true | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-crabbox-v2026-293-1001/crabbox.md b/src/content/docs/reference/candy/github-com-opencharly-layer-crabbox-v2026-293-1001/crabbox.md new file mode 100644 index 00000000..e0de9312 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-crabbox-v2026-293-1001/crabbox.md @@ -0,0 +1,40 @@ +--- +title: "crabbox" +description: "The Crabbox CLI — lease, sync, run, stream, and release remote test execution (https://github.com/openclaw/crabbox)." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-crabbox:v2026.293.1001` | + +The Crabbox CLI — lease, sync, run, stream, and release remote test +execution (https://github.com/openclaw/crabbox). Installs the single +static `crabbox` binary from the pinned GoReleaser release archive to +/usr/local/bin/crabbox, and composes the CLI's laptop prerequisites +instead of re-shipping them (R3): git via layer-gh, ssh/ssh-keygen via +layer-ssh-client, plus rsync/curl packages. The observable, verifiable +effect — the binary at a fixed path, `crabbox --version` reporting the +pinned release, the credential-free `crabbox providers` matrix, and a +broker-less `crabbox doctor` pass — is exactly what the plan block +asserts; a missing download or a broken binary fails the checks. + +## Packages + +Installed on every distro: + +- `rsync` +- `curl` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | download the pinned crabbox release archive and install the single binary to /usr/local/bin | +| `check` | the crabbox CLI binary is installed at /usr/local/bin/crabbox | +| `check` | crabbox --version reports the pinned 0.79.0 release on stdout | +| `check` | crabbox providers lists the credential-free local provider matrix | +| `check` | crabbox doctor passes in a broker-less context (local prerequisites only) | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-cuda-v2026-290-1513/cuda.md b/src/content/docs/reference/candy/github-com-opencharly-layer-cuda-v2026-290-1513/cuda.md new file mode 100644 index 00000000..9c264e76 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-cuda-v2026-290-1513/cuda.md @@ -0,0 +1,37 @@ +--- +title: "cuda" +description: "CUDA toolkit (nvcc, cudart, cuDNN, onnxruntime) stitched into the canonical /usr layout on Fedora and Arch Installs the CUDA compiler driver (nvcc), the CUDA runtime/dev libraries (cudart, nvrtc, cupti, curand, cccl, cufile), cuDNN, and onnxruntime." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-cuda:v2026.290.1513` | + +CUDA toolkit (nvcc, cudart, cuDNN, onnxruntime) stitched into the canonical /usr layout on Fedora and Arch +Installs the CUDA compiler driver (nvcc), the CUDA runtime/dev +libraries (cudart, nvrtc, cupti, curand, cccl, cufile), cuDNN, and +onnxruntime. On Fedora the RPMs land in /usr directly; on Arch the +post-install tasks symlink the /opt/cuda binaries, headers, and libs +into the same /usr-rooted paths, so every downstream GPU consumer +compiles against one layout regardless of distro. Each artifact is a +real file or library on disk, so its presence is directly verifiable. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | command=if [ ! -f /etc/fedora-release ]; then exit 0 fi CUDNN_DIR=$(mktemp -d) cd "$CUDNN_DIR" if dnf5 download --enable-repo="fedora-multimedia" cuda-cudnn-devel 2>/dev/null; then rpm2cpio cuda-cudnn-devel*.rpm \| cpio -idm 2>/dev/null [ -d ./usr/include ] && cp -v ./usr/include/cudnn*.h /usr/include/ while IFS= read -r -d '' link; do name=$(basename "$link") versioned="" for v in /usr/lib64/"${name}".*; do if [ -f "$v" ] && ! echo "$v" \| grep -q '\.so$'; then versioned="$v"; break fi done [ -n "$versioned" ] && [ ! -e /usr/lib64/"$name" ] && ln -sv "$(basename "$versioned")" /usr/lib64/"$name" done < <(find ./usr/lib64 -maxdepth 1 -name '*.so' -type l -print0 2>/dev/null) fi cd / && rm -rf "$CUDNN_DIR" | +| `run` | command=if [ ! -f /etc/arch-release ]; then exit 0 fi # nvcc + cuobjdump + ptxas + nvprof — every binary in /opt/cuda/bin for bin in /opt/cuda/bin/*; do [ -e "$bin" ] && ln -sf "$bin" /usr/bin/$(basename "$bin") done # Headers — cudnn*.h live in /opt/cuda/targets/x86_64-linux/include # on the cudnn package, while CUDA's own headers live in # /opt/cuda/include. Symlink both into /usr/include. # Headers — link EVERY ENTRY of each toolkit include root, not a guessed subset. # nvcc computes its default include root RELATIVE to its own executable, and # /usr/bin/nvcc is a symlink, so all CUDA headers must be reachable under # /usr/include. Enumerating by pattern is what broke this: a `*.h` glob linked the # top-level headers but silently dropped (a) the SUBTREES crt/ and cccl/, which # killed every build at CMake's enable_language(CUDA) with "crt/host_config.h: No # such file or directory", and then (b) the `.hpp` half of the `_functions` family # (`vector_functions.hpp` and friends), which killed the very next stage -- both # reported on opencharly/layer-cuda#9. Linking every entry needs no extension list # to keep in sync and cannot silently miss a file or a subtree again. # nvcc resolves its OWN helpers relative to its own executable path. Through the # /usr/bin/nvcc symlink that means /usr// — so the toolkit's sibling TREES # must exist at /usr too, not only its files. Without /usr/nvvm, nvcc cannot find its # backend compiler at all: "$CICC_PATH/cicc: No such file or directory" # (/usr/sbin/../nvvm/bin/cicc), and every CUDA compile dies while PREPROCESSING # still succeeds — which is exactly how the check added in #10 stayed green through # it. Both halves of that lesson are fixed here. for tree in nvvm; do [ -d "/opt/cuda/$tree" ] && [ ! -e "/usr/$tree" ] && ln -sfn "/opt/cuda/$tree" "/usr/$tree" done for root in /opt/cuda/include /opt/cuda/targets/x86_64-linux/include; do [ -d "$root" ] \|\| continue for entry in "$root"/*; do [ -e "$entry" ] \|\| continue ln -sfn "$entry" /usr/include/"$(basename "$entry")" done done # Libraries: libcudart, libcudnn, libcurand, etc. mkdir -p /usr/lib64 # Enumerate EVERY entry, not a `*.so*` glob. nvcc links the STATIC archives by # default (libcudart_static.a, libcudadevrt.a, libculibos.a, ...), and a `.so*` # pattern cannot match a `.a` — so the linker failed with "cannot find # -lcudart_static: No such file or directory" although the package ships the file # (opencharly/layer-cuda#12). Same defect shape as the `*.h` header glob that missed # `.hpp`: pattern-matching a directory instead of enumerating it. mkdir -p /usr/lib64 for libdir in /opt/cuda/targets/x86_64-linux/lib /opt/cuda/lib64; do [ -d "$libdir" ] \|\| continue for entry in "$libdir"/*; do [ -e "$entry" ] \|\| continue ln -sfn "$entry" /usr/lib64/"$(basename "$entry")" done done | +| `check` | the nvcc CUDA compiler driver is on the canonical /usr path | +| `check` | nvcc reports its CUDA compilation-tools release | +| `check` | the cuDNN header is available at /usr/include regardless of distro | +| `check` | a CUDA translation unit COMPILES AND LINKS against the stitched /usr layout (Arch: the header subtrees are linked, not only the top-level files) | +| `check` | the CUDA runtime library is linkable from the canonical /usr/lib64 path | +| `agent-check` | downstream GPU layers (llama-cpp, vllm, comfyui, jupyter-ml) compile against the same /usr-rooted CUDA layout on both Fedora and Arch | +| `check` | package=cuda-cudart-devel | +| `check` | command=ls /usr/include/cudnn.h | +| `check` | package=onnxruntime | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-cuda-v2026-290-2052/cuda.md b/src/content/docs/reference/candy/github-com-opencharly-layer-cuda-v2026-290-2052/cuda.md new file mode 100644 index 00000000..5b307bfc --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-cuda-v2026-290-2052/cuda.md @@ -0,0 +1,37 @@ +--- +title: "cuda" +description: "CUDA toolkit (nvcc, cudart, cuDNN, onnxruntime) stitched into the canonical /usr layout on Fedora and Arch Installs the CUDA compiler driver (nvcc), the CUDA runtime/dev libraries (cudart, nvrtc, cupti, curand, cccl, cufile), cuDNN, and onnxruntime." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-cuda:v2026.290.2052` | + +CUDA toolkit (nvcc, cudart, cuDNN, onnxruntime) stitched into the canonical /usr layout on Fedora and Arch +Installs the CUDA compiler driver (nvcc), the CUDA runtime/dev +libraries (cudart, nvrtc, cupti, curand, cccl, cufile), cuDNN, and +onnxruntime. On Fedora the RPMs land in /usr directly; on Arch the +post-install tasks symlink the /opt/cuda binaries, headers, and libs +into the same /usr-rooted paths, so every downstream GPU consumer +compiles against one layout regardless of distro. Each artifact is a +real file or library on disk, so its presence is directly verifiable. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | command=if [ ! -f /etc/fedora-release ]; then exit 0 fi CUDNN_DIR=$(mktemp -d) cd "$CUDNN_DIR" if dnf5 download --enable-repo="fedora-multimedia" cuda-cudnn-devel 2>/dev/null; then rpm2cpio cuda-cudnn-devel*.rpm \| cpio -idm 2>/dev/null [ -d ./usr/include ] && cp -v ./usr/include/cudnn*.h /usr/include/ while IFS= read -r -d '' link; do name=$(basename "$link") versioned="" for v in /usr/lib64/"${name}".*; do if [ -f "$v" ] && ! echo "$v" \| grep -q '\.so$'; then versioned="$v"; break fi done [ -n "$versioned" ] && [ ! -e /usr/lib64/"$name" ] && ln -sv "$(basename "$versioned")" /usr/lib64/"$name" done < <(find ./usr/lib64 -maxdepth 1 -name '*.so' -type l -print0 2>/dev/null) fi cd / && rm -rf "$CUDNN_DIR" | +| `run` | command=if [ ! -f /etc/arch-release ]; then exit 0 fi # nvcc + cuobjdump + ptxas + nvprof — every binary in /opt/cuda/bin for bin in /opt/cuda/bin/*; do [ -e "$bin" ] && ln -sf "$bin" /usr/bin/$(basename "$bin") done # Headers — cudnn*.h live in /opt/cuda/targets/x86_64-linux/include # on the cudnn package, while CUDA's own headers live in # /opt/cuda/include. Symlink both into /usr/include. # Headers — link EVERY ENTRY of each toolkit include root, not a guessed subset. # nvcc computes its default include root RELATIVE to its own executable, and # /usr/bin/nvcc is a symlink, so all CUDA headers must be reachable under # /usr/include. Enumerating by pattern is what broke this: a `*.h` glob linked the # top-level headers but silently dropped (a) the SUBTREES crt/ and cccl/, which # killed every build at CMake's enable_language(CUDA) with "crt/host_config.h: No # such file or directory", and then (b) the `.hpp` half of the `_functions` family # (`vector_functions.hpp` and friends), which killed the very next stage -- both # reported on opencharly/layer-cuda#9. Linking every entry needs no extension list # to keep in sync and cannot silently miss a file or a subtree again. # nvcc resolves its OWN helpers relative to its own executable path. Through the # /usr/bin/nvcc symlink that means /usr// — so the toolkit's sibling TREES # must exist at /usr too, not only its files. Without /usr/nvvm, nvcc cannot find its # backend compiler at all: "$CICC_PATH/cicc: No such file or directory" # (/usr/sbin/../nvvm/bin/cicc), and every CUDA compile dies while PREPROCESSING # still succeeds — which is exactly how the check added in #10 stayed green through # it. Both halves of that lesson are fixed here. for tree in nvvm; do [ -d "/opt/cuda/$tree" ] && [ ! -e "/usr/$tree" ] && ln -sfn "/opt/cuda/$tree" "/usr/$tree" done for root in /opt/cuda/include /opt/cuda/targets/x86_64-linux/include; do [ -d "$root" ] \|\| continue for entry in "$root"/*; do [ -e "$entry" ] \|\| continue ln -sfn "$entry" /usr/include/"$(basename "$entry")" done done # Libraries: libcudart, libcudnn, libcurand, etc. mkdir -p /usr/lib64 # Enumerate EVERY entry, not a `*.so*` glob. nvcc links the STATIC archives by # default (libcudart_static.a, libcudadevrt.a, libculibos.a, ...), and a `.so*` # pattern cannot match a `.a` — so the linker failed with "cannot find # -lcudart_static: No such file or directory" although the package ships the file # (opencharly/layer-cuda#12). Same defect shape as the `*.h` header glob that missed # `.hpp`: pattern-matching a directory instead of enumerating it. mkdir -p /usr/lib64 for libdir in /opt/cuda/targets/x86_64-linux/lib /opt/cuda/lib64; do [ -d "$libdir" ] \|\| continue for entry in "$libdir"/*; do [ -e "$entry" ] \|\| continue ln -sfn "$entry" /usr/lib64/"$(basename "$entry")" done done | +| `check` | the nvcc CUDA compiler driver is on the canonical /usr path | +| `check` | nvcc reports its CUDA compilation-tools release | +| `check` | the cuDNN header is available at /usr/include regardless of distro | +| `check` | a CUDA translation unit COMPILES AND LINKS against the stitched /usr layout (Arch: the header subtrees are linked, not only the top-level files) | +| `check` | the CUDA runtime library is linkable from the canonical /usr/lib64 path | +| `agent-check` | downstream GPU layers (llama-cpp, vllm, comfyui, jupyter-ml) compile against the same /usr-rooted CUDA layout on both Fedora and Arch | +| `check` | package=cuda-cudart-devel | +| `check` | command=ls /usr/include/cudnn.h | +| `check` | package=onnxruntime | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-nvidia-054aa7702ebe79e8be444764f91a03933ba45eec/nvidia.md b/src/content/docs/reference/candy/github-com-opencharly-layer-nvidia-054aa7702ebe79e8be444764f91a03933ba45eec/nvidia.md new file mode 100644 index 00000000..f4c735cc --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-nvidia-054aa7702ebe79e8be444764f91a03933ba45eec/nvidia.md @@ -0,0 +1,41 @@ +--- +title: "nvidia" +description: "NVIDIA GPU runtime — nvidia-container-toolkit (nvidia-ctk CDI) plus the driver-lib path and Vulkan ICD wiring Installs nvidia-container-toolkit (the nvidia-ctk CLI that generates CDI device specs) alongside the per-distro driver libs (nvidia-utils on Arch, libva-nvidia-driver on Fedora)." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-nvidia:054aa7702ebe79e8be444764f91a03933ba45eec` | + +NVIDIA GPU runtime — nvidia-container-toolkit (nvidia-ctk CDI) plus the driver-lib path and Vulkan ICD wiring +Installs nvidia-container-toolkit (the nvidia-ctk CLI that generates +CDI device specs) alongside the per-distro driver libs (nvidia-utils +on Arch, libva-nvidia-driver on Fedora). Exports +LD_LIBRARY_PATH=/usr/lib64 so the GPU driver libraries resolve, and +prepares /etc/vulkan/icd.d to hold the nvidia Vulkan ICD symlinks. +Every effect — the package, the nvidia-ctk binary, the exported path, +and the ICD directory — is a real artifact baked into the image, so +each is directly verifiable without a physical GPU. + +## Packages + +Installed on every distro: + +- `nvidia-container-toolkit` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | mkdir=/etc/vulkan/icd.d | +| `run` | command=[ -f /usr/share/vulkan/icd.d/nvidia_icd.x86_64.json ] && \ ln -sf /usr/share/vulkan/icd.d/nvidia_icd.x86_64.json /etc/vulkan/icd.d/nvidia_icd.json \|\| true [ -f /usr/share/vulkan/implicit_layer.d/nvidia_layers.json ] && \ ln -sf /usr/share/vulkan/implicit_layer.d/nvidia_layers.json /etc/vulkan/icd.d/nvidia_layers.json \|\| true | +| `check` | the nvidia-container-toolkit repo enforces package signature verification, so its packages cannot install unverified | +| `check` | the nvidia-container-toolkit package is installed for CDI device generation | +| `check` | the nvidia-ctk CLI binary lands on the canonical /usr/bin path | +| `check` | nvidia-ctk runs and reports a version number | +| `check` | the Vulkan ICD directory exists to hold the nvidia ICD symlinks | +| `check` | the nvidia userspace for THIS distro is present, either the Arch driver libs from nvidia-utils or the Fedora VA-API driver from libva-nvidia-driver | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-nvidia-7766a9d06ec5fe8c276c091a68fb72cea12688e3/nvidia.md b/src/content/docs/reference/candy/github-com-opencharly-layer-nvidia-7766a9d06ec5fe8c276c091a68fb72cea12688e3/nvidia.md new file mode 100644 index 00000000..0614dbf9 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-nvidia-7766a9d06ec5fe8c276c091a68fb72cea12688e3/nvidia.md @@ -0,0 +1,41 @@ +--- +title: "nvidia" +description: "NVIDIA GPU runtime — nvidia-container-toolkit (nvidia-ctk CDI) plus the driver-lib path and Vulkan ICD wiring Installs nvidia-container-toolkit (the nvidia-ctk CLI that generates CDI device specs) alongside the per-distro driver libs (nvidia-utils on Arch, libva-nvidia-driver on Fedora)." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-nvidia:7766a9d06ec5fe8c276c091a68fb72cea12688e3` | + +NVIDIA GPU runtime — nvidia-container-toolkit (nvidia-ctk CDI) plus the driver-lib path and Vulkan ICD wiring +Installs nvidia-container-toolkit (the nvidia-ctk CLI that generates +CDI device specs) alongside the per-distro driver libs (nvidia-utils +on Arch, libva-nvidia-driver on Fedora). Exports +LD_LIBRARY_PATH=/usr/lib64 so the GPU driver libraries resolve, and +prepares /etc/vulkan/icd.d to hold the nvidia Vulkan ICD symlinks. +Every effect — the package, the nvidia-ctk binary, the exported path, +and the ICD directory — is a real artifact baked into the image, so +each is directly verifiable without a physical GPU. + +## Packages + +Installed on every distro: + +- `nvidia-container-toolkit` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | mkdir=/etc/vulkan/icd.d | +| `run` | command=[ -f /usr/share/vulkan/icd.d/nvidia_icd.x86_64.json ] && \ ln -sf /usr/share/vulkan/icd.d/nvidia_icd.x86_64.json /etc/vulkan/icd.d/nvidia_icd.json \|\| true [ -f /usr/share/vulkan/implicit_layer.d/nvidia_layers.json ] && \ ln -sf /usr/share/vulkan/implicit_layer.d/nvidia_layers.json /etc/vulkan/icd.d/nvidia_layers.json \|\| true | +| `check` | the nvidia-container-toolkit repo enforces package signature verification, so its packages cannot install unverified | +| `check` | the nvidia-container-toolkit package is installed for CDI device generation | +| `check` | the nvidia-ctk CLI binary lands on the canonical /usr/bin path | +| `check` | nvidia-ctk runs and reports a version number | +| `check` | the Vulkan ICD directory exists to hold the nvidia ICD symlinks | +| `check` | the nvidia userspace for THIS distro is present, either the Arch driver libs from nvidia-utils or the Fedora VA-API driver from libva-nvidia-driver | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-nvidia-v2026-289-1705/nvidia.md b/src/content/docs/reference/candy/github-com-opencharly-layer-nvidia-v2026-289-1705/nvidia.md new file mode 100644 index 00000000..2059e8d4 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-nvidia-v2026-289-1705/nvidia.md @@ -0,0 +1,41 @@ +--- +title: "nvidia" +description: "NVIDIA GPU runtime — nvidia-container-toolkit (nvidia-ctk CDI) plus the driver-lib path and Vulkan ICD wiring Installs nvidia-container-toolkit (the nvidia-ctk CLI that generates CDI device specs) alongside the per-distro driver libs (nvidia-utils on Arch, libva-nvidia-driver on Fedora)." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-nvidia:v2026.289.1705` | + +NVIDIA GPU runtime — nvidia-container-toolkit (nvidia-ctk CDI) plus the driver-lib path and Vulkan ICD wiring +Installs nvidia-container-toolkit (the nvidia-ctk CLI that generates +CDI device specs) alongside the per-distro driver libs (nvidia-utils +on Arch, libva-nvidia-driver on Fedora). Exports +LD_LIBRARY_PATH=/usr/lib64 so the GPU driver libraries resolve, and +prepares /etc/vulkan/icd.d to hold the nvidia Vulkan ICD symlinks. +Every effect — the package, the nvidia-ctk binary, the exported path, +and the ICD directory — is a real artifact baked into the image, so +each is directly verifiable without a physical GPU. + +## Packages + +Installed on every distro: + +- `nvidia-container-toolkit` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | mkdir=/etc/vulkan/icd.d | +| `run` | command=[ -f /usr/share/vulkan/icd.d/nvidia_icd.x86_64.json ] && \ ln -sf /usr/share/vulkan/icd.d/nvidia_icd.x86_64.json /etc/vulkan/icd.d/nvidia_icd.json \|\| true [ -f /usr/share/vulkan/implicit_layer.d/nvidia_layers.json ] && \ ln -sf /usr/share/vulkan/implicit_layer.d/nvidia_layers.json /etc/vulkan/icd.d/nvidia_layers.json \|\| true | +| `check` | the nvidia-container-toolkit repo enforces package signature verification, so its packages cannot install unverified | +| `check` | the nvidia-container-toolkit package is installed for CDI device generation | +| `check` | the nvidia-ctk CLI binary lands on the canonical /usr/bin path | +| `check` | nvidia-ctk runs and reports a version number | +| `check` | the Vulkan ICD directory exists to hold the nvidia ICD symlinks | +| `check` | the nvidia userspace for THIS distro is present, either the Arch driver libs from nvidia-utils or the Fedora VA-API driver from libva-nvidia-driver | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-python-ml-v2026-290-1914/python-ml.md b/src/content/docs/reference/candy/github-com-opencharly-layer-python-ml-v2026-290-1914/python-ml.md new file mode 100644 index 00000000..fe5d3e13 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-python-ml-v2026-290-1914/python-ml.md @@ -0,0 +1,35 @@ +--- +title: "python-ml" +description: "A CUDA-ready Python 3.13 ML environment with PyTorch, transformers, and a vLLM inference runtime The python-ml candy owns the pixi.toml that builds the core ML Python environment under ~/.pixi/envs/default: PyTorch (cu130), torchvision/torchaudio, transformers, accelerate and the full vLLM runtime-dependency closure." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-python-ml:v2026.290.1914` | + +A CUDA-ready Python 3.13 ML environment with PyTorch, transformers, and a vLLM inference runtime +The python-ml candy owns the pixi.toml that builds the core ML +Python environment under ~/.pixi/envs/default: PyTorch (cu130), +torchvision/torchaudio, transformers, accelerate and the full vLLM +runtime-dependency closure. After the pixi environment is built, a +user-phase task pip-installs the vLLM nightly wheel (--no-deps) into +that same interpreter. Every interpreter and library lands at a +fixed path under ~/.pixi/envs/default, so its presence and +importability are directly checkable. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | command=~/.pixi/envs/default/bin/python -m pip install --no-deps \ 'https://wheels.vllm.ai/f53fa26e05c476a43f6db048a9e3b43bcb2b72fb/vllm-0.19.1rc1.dev39%2Bgf53fa26e0.cu130-cp38-abi3-manylinux_2_35_x86_64.whl' | +| `check` | the pixi default-environment Python interpreter is present | +| `check` | PyTorch imports inside the pixi environment and prints its version | +| `check` | the transformers library imports inside the pixi environment and prints its version | +| `check` | the vLLM nightly wheel installed by the user-phase task imports and prints its version | +| `check` | command=${HOME}/.pixi/envs/default/bin/python -c "import torch; print(torch.__version__)" | +| `check` | command=${HOME}/.pixi/envs/default/bin/python -c "import vllm; print(vllm.__version__)" | +| `check` | command=${HOME}/.pixi/envs/default/bin/python -c "import transformers; print(transformers.__version__)" | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-python-v2026-293-1922/python.md b/src/content/docs/reference/candy/github-com-opencharly-layer-python-v2026-293-1922/python.md new file mode 100644 index 00000000..a7f648bd --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-python-v2026-293-1922/python.md @@ -0,0 +1,33 @@ +--- +title: "python" +description: "A CPython interpreter provided as a pixi-managed conda-forge environment." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-python:v2026.293.1922` | + +A CPython interpreter provided as a pixi-managed conda-forge environment. +The python candy ships a pixi.toml that pins python >=3.13,<3.14 from +conda-forge, and a pixi builder stage materializes the environment at +~/.pixi/envs/default, so the CPython interpreter lands at a fixed, +PATH-contributed path. +The image's environment belongs to whichever candy ships the pixi.toml it +is built from, so a consuming image may legitimately pin a different minor +than this default — open-webui, for one, requires <3.13. The checks +therefore assert what the layer actually guarantees: a working CPython at +or above the supported floor of 3.11, verified by file existence, the +version it reports, and real standard-library code including the sqlite3 C +extension. An image that needs an exact minor asserts it in its own plan. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `check` | the pixi-managed CPython interpreter exists at the default environment bin path | +| `check` | the interpreter is a CPython at or above the supported floor (3.11) — the exact minor belongs to whichever candy owns the image's pixi.toml, not to this layer | +| `check` | the interpreter executes a standard-library snippet (incl. the sqlite3 C extension) and satisfies the same floor | diff --git a/src/content/docs/reference/candy/github-com-opencharly-layer-whisper-v2026-290-1729/whisper.md b/src/content/docs/reference/candy/github-com-opencharly-layer-whisper-v2026-290-1729/whisper.md new file mode 100644 index 00000000..2ed1540b --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-layer-whisper-v2026-290-1729/whisper.md @@ -0,0 +1,26 @@ +--- +title: "whisper" +description: "OpenAI Whisper local speech-to-text CLI (GPU-capable) Installs openai-whisper via pixi into the default env, composing the python + cuda + ffmpeg candies (ffmpeg is required for audio decoding)." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/layer-whisper:v2026.290.1729` | + +OpenAI Whisper local speech-to-text CLI (GPU-capable) +Installs openai-whisper via pixi into the default env, composing the +python + cuda + ffmpeg candies (ffmpeg is required for audio +decoding). Verifiable: the whisper CLI lands in the pixi default env, +runs `--help`, and ffmpeg is available for decoding. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `check` | the whisper CLI is installed in the pixi default env | +| `check` | the whisper CLI runs and prints its usage | +| `check` | ffmpeg is available on PATH for audio decoding | diff --git a/src/content/docs/reference/candy/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box.md b/src/content/docs/reference/candy/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box.md similarity index 95% rename from src/content/docs/reference/candy/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box.md rename to src/content/docs/reference/candy/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box.md index 9966c729..632efc0d 100644 --- a/src/content/docs/reference/candy/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box.md +++ b/src/content/docs/reference/candy/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box.md @@ -7,8 +7,8 @@ description: "The build-mode `charly box …` verb HANDLERS relocated into a COM | | | |---|---| -| **Repo** | `box/github.com/opencharly/plugin-box:v2026.288.0503` | -| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Repo** | `box/github.com/opencharly/plugin-box:v2026.301.1542` | +| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | The build-mode `charly box …` verb HANDLERS relocated into a COMPILED-IN command plugin candy (P15, K5). `charly box` is a SHARED command group whose subcommands have different diff --git a/src/content/docs/reference/candy/github-com-opencharly-plugin-build-v2026-287-2220/plugin-build.md b/src/content/docs/reference/candy/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build.md similarity index 87% rename from src/content/docs/reference/candy/github-com-opencharly-plugin-build-v2026-287-2220/plugin-build.md rename to src/content/docs/reference/candy/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build.md index ab183509..ed253ca3 100644 --- a/src/content/docs/reference/candy/github-com-opencharly-plugin-build-v2026-287-2220/plugin-build.md +++ b/src/content/docs/reference/candy/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build.md @@ -7,8 +7,8 @@ description: "The BUILD-DRIVE plugin: it OWNS the build drive — BuildKit is th | | | |---|---| -| **Repo** | `box/github.com/opencharly/plugin-build:v2026.287.2220` | -| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-build-v2026-287-2220/plugin-build/) | +| **Repo** | `box/github.com/opencharly/plugin-build:v2026.293.0926` | +| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build/) | The BUILD-DRIVE plugin: it OWNS the build drive — BuildKit is the builder (the build-order loop, the per-image build lock, the push, and the merge gate) for `build:box` (the `charly box @@ -22,9 +22,11 @@ NewGenerator this candy used to call over HostBuild is DELETED, #55 step3 3-II), the host only for what a sdk-only candy structurally cannot do (the bootstrap-delicate local scan, the git fetch, the build-time plugin connect, the host-fs prep) over a small `buildengine-*` HostBuild leg family; the layer MERGE crosses to verb:oci via -InvokeProvider (no HostBuild("merge") seam). The candy then runs podman directly — -building each image (Containerfile piped over stdin), gating the inline merge on the -box's MergeAuto, and pushing (podman) after merge; build:generate renders the .build/ +InvokeProvider (no HostBuild("merge") seam). Each stage is built with BuildKit and its +image is STORED IN THE CONFIGURED CONTAINER BACKEND (the SDK `LoadExport`), then pushed +to the LOCAL CHARLY OCI REGISTRY under the same FullTag, which the daemon mirrors +`ghcr.io/opencharly` to — so the next stage's `FROM` resolves an internal base locally, +never against the upstream registry. build:generate renders the .build/ Containerfile tree in its own code (via sdk/deploykit, #67) and returns the written paths (no podman, no merge); build:ensure resolves a project-authored image identifier against charly.yml PLUGIN-SIDE (loaderkit.LoadUnified via the K1 loader reverse legs — diff --git a/src/content/docs/reference/candy/github-com-opencharly-plugin-check-v2026-287-1745/plugin-check.md b/src/content/docs/reference/candy/github-com-opencharly-plugin-check-v2026-298-0205/plugin-check.md similarity index 96% rename from src/content/docs/reference/candy/github-com-opencharly-plugin-check-v2026-287-1745/plugin-check.md rename to src/content/docs/reference/candy/github-com-opencharly-plugin-check-v2026-298-0205/plugin-check.md index 044c1f54..a34c9b7b 100644 --- a/src/content/docs/reference/candy/github-com-opencharly-plugin-check-v2026-287-1745/plugin-check.md +++ b/src/content/docs/reference/candy/github-com-opencharly-plugin-check-v2026-298-0205/plugin-check.md @@ -7,8 +7,8 @@ description: "COMPILED-IN charly COMMAND-class plugin that OWNS the externalized | | | |---|---| -| **Repo** | `box/github.com/opencharly/plugin-check:v2026.287.1745` | -| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-check-v2026-287-1745/plugin-check/) | +| **Repo** | `box/github.com/opencharly/plugin-check:v2026.298.0205` | +| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-check-v2026-298-0205/plugin-check/) | COMPILED-IN charly COMMAND-class plugin that OWNS the externalized `charly check` command family (P12) — the box/live/run/feature evaluation surface plus the AI-iteration diff --git a/src/content/docs/reference/candy/github-com-opencharly-plugin-crabbox-v2026-293-1011/plugin-crabbox.md b/src/content/docs/reference/candy/github-com-opencharly-plugin-crabbox-v2026-293-1011/plugin-crabbox.md new file mode 100644 index 00000000..3e736328 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-plugin-crabbox-v2026-293-1011/plugin-crabbox.md @@ -0,0 +1,50 @@ +--- +title: "plugin-crabbox" +description: "OUT-OF-TREE charly plugin serving the `crabbox` check verb — a standalone Go module (go.mod + main.go) that probes the Crabbox CLI and its optional local coordinator, served OUT-OF-PROCESS over go-plugin gRPC via the charly plugin SDK (github.com/opencharly/sdk)." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/plugin-crabbox:v2026.293.1011` | +| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-crabbox-v2026-293-1011/plugin-crabbox/) | + +OUT-OF-TREE charly plugin serving the `crabbox` check verb — a standalone +Go module (go.mod + main.go) that probes the Crabbox CLI and its optional +local coordinator, served OUT-OF-PROCESS over go-plugin gRPC via the charly +plugin SDK (github.com/opencharly/sdk). charly's loader fetches this candy's +repo, go-builds the provider binary on the HOST, and serves it via +LocalTransport — so an authored `crabbox:` step dispatches through the +provider registry exactly like a built-in. + +The verb has THREE method classes. In-venue CLI methods (version/providers/ +config/doctor — credential-free — and leases/usage/events/logs — +broker-backed, requiring a `crabbox login` in the venue) run the `crabbox` +binary INSIDE the venue over the reverse channel (cc.Exec). Coordinator +HTTP probe methods (health/ready) hit the Node.js/PostgreSQL coordinator's +/v1/health and /v1/ready endpoints — the container-probe surface the +coordinator exposes — from the charly host against the resolved endpoint +(cc.ResolveEndpoint + cc.HTTPDo, one authored step works unchanged against a +pod's published port and a VM's forwarded one). All methods are read-only; +there are no mutating methods in this first cut. + +It is NOT a re-skin of the generic `command:`/`http:` verbs: this plugin +exists for what those structurally cannot do — ENDPOINT RESOLUTION +(cc.ResolveEndpoint for the coordinator probes) and DOMAIN SEMANTICS +(methods map to the crabbox CLI's real surface and return real verdicts, +with `json_path:` to assert one field; the in-venue CLI methods reach the +binary where it is installed, which `http:` cannot). + +The R10 consumers are the crabbox-bearing beds (check-crabbox-pod and +check-crabbox-e2e-pod) whose checks compose this plugin alongside the +`crabbox` CLI candy from opencharly/layer-crabbox and the coordinator candy +from opencharly/pod-crabbox. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `check` | the crabbox verb dispatches through the provider registry and reports the pinned CLI version on a live deployment | diff --git a/src/content/docs/reference/candy/github-com-opencharly-plugin-migrate-v2026-280-2238/plugin-migrate.md b/src/content/docs/reference/candy/github-com-opencharly-plugin-migrate-v2026-295-1526/plugin-migrate.md similarity index 95% rename from src/content/docs/reference/candy/github-com-opencharly-plugin-migrate-v2026-280-2238/plugin-migrate.md rename to src/content/docs/reference/candy/github-com-opencharly-plugin-migrate-v2026-295-1526/plugin-migrate.md index 5ce1edb9..926e3ba0 100644 --- a/src/content/docs/reference/candy/github-com-opencharly-plugin-migrate-v2026-280-2238/plugin-migrate.md +++ b/src/content/docs/reference/candy/github-com-opencharly-plugin-migrate-v2026-295-1526/plugin-migrate.md @@ -7,8 +7,8 @@ description: "COMPILED-IN charly plugin owning the config-schema MIGRATION ENGIN | | | |---|---| -| **Repo** | `box/github.com/opencharly/plugin-migrate:v2026.280.2238` | -| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-migrate-v2026-280-2238/plugin-migrate/) | +| **Repo** | `box/github.com/opencharly/plugin-migrate:v2026.295.1526` | +| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-migrate-v2026-295-1526/plugin-migrate/) | COMPILED-IN charly plugin owning the config-schema MIGRATION ENGINE (M15 — migrate OUT of core). It serves ONE capability: diff --git a/src/content/docs/reference/candy/github-com-opencharly-plugin-ollama-v2026-289-0014/plugin-ollama.md b/src/content/docs/reference/candy/github-com-opencharly-plugin-ollama-v2026-289-0014/plugin-ollama.md new file mode 100644 index 00000000..15c6cac8 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-plugin-ollama-v2026-289-0014/plugin-ollama.md @@ -0,0 +1,46 @@ +--- +title: "plugin-ollama" +description: "COMPILED-IN charly COMMAND-class plugin (command:ollama) OWNING the entire `charly ollama` CLI — the host-side management surface for a DEPLOYED Ollama server: list / ps / pull / rm / show / cp / create / push / run / stop / version." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/plugin-ollama:v2026.289.0014` | +| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-ollama-v2026-289-0014/plugin-ollama/) | + +COMPILED-IN charly COMMAND-class plugin (command:ollama) OWNING the entire +`charly ollama` CLI — the host-side management surface for a DEPLOYED Ollama +server: list / ps / pull / rm / show / cp / create / push / run / stop / +version. The plugin owns the ENTIRE logic: the hand-rolled subcommand grammar +AND the Ollama HTTP API calls, built on the official upstream Go client +(github.com/ollama/ollama/api, pinned in the candy's own go.mod). There is NO +core ollama logic and NO HostBuild seam. + +The command talks to the server over plain HTTP, so it is fully self-contained +and works IDENTICALLY compiled-in OR out-of-process: listed in charly.yml +compiled_plugins it registers in-proc and the host dispatches it through +dispatchInProcCommand → Invoke(OpRun) → runOllamaCLI; the out-of-process +placement fork/execs cmd/serve → CliMain running the SAME runOllamaCLI. +Endpoint resolution is deliberately lightweight: --server flag > OLLAMA_HOST env +> http://127.0.0.1:11434. + +This is a sibling of the ollama CANDY (candy/ollama — which deploys the +server) and of the candy's host shell `alias: ollama` (which execs the +upstream CLI inside the container): three disjoint surfaces. Full Modelfile +authoring stays with the upstream CLI; `charly ollama create` covers the +lightweight --from form. + +The R10 witness is the disposable check-ollama-pod bed (box/fedora): it deploys +the ollama image and runs `charly ollama list|version --server +http://127.0.0.1:${HOST_PORT:11434}` host-side against the live server, plus +the candy's baked checks. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `check` | the command plugin ships a buildable Go module (go.mod + the provider) the host can build; the full `charly ollama` end-to-end is exercised by the live R10 bed (check-ollama-pod) | diff --git a/src/content/docs/reference/candy/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task.md b/src/content/docs/reference/candy/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task.md similarity index 93% rename from src/content/docs/reference/candy/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task.md rename to src/content/docs/reference/candy/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task.md index 6093dcf3..75048230 100644 --- a/src/content/docs/reference/candy/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task.md +++ b/src/content/docs/reference/candy/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task.md @@ -7,8 +7,8 @@ description: "The generic declarative TASK runner for charly — the replacement | | | |---|---| -| **Repo** | `box/github.com/opencharly/plugin-task:v2026.283.0105` | -| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task/) | +| **Repo** | `box/github.com/opencharly/plugin-task:v2026.300.0951` | +| **Plugin** | yes — see the [plugin reference](/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task/) | The generic declarative TASK runner for charly — the replacement for a Taskfile. Serves three task capabilities plus five generic maintenance @@ -27,7 +27,7 @@ which a self-contained plugin schema cannot carry). Five GENERIC, domain-neutral MAINTENANCE verbs replace repository shell scripts, each parameterized by the repo's own data (paths/pairs/pins) so the plugin stays reusable by any repository: `verb:git-submodules` (status/bump/ -verify `.gitmodules` pins, incl. the policy-B comparison of a repo's pins +verify `.gitmodules` pins, incl. the EDGE comparison of a repo's pins against a pinned checkout's gitlinks), `verb:file-parity` (check/sync that paired files are byte-identical), `verb:splice-region` (splice a marked region from a fragment into a target), `verb:module-pins` (adopt a diff --git a/src/content/docs/reference/candy/github-com-opencharly-pod-airflow-v2026-290-2110/airflow.md b/src/content/docs/reference/candy/github-com-opencharly-pod-airflow-v2026-290-2110/airflow.md new file mode 100644 index 00000000..028a8c4e --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-pod-airflow-v2026-290-2110/airflow.md @@ -0,0 +1,54 @@ +--- +title: "airflow" +description: "Apache Airflow runs single-node (LocalExecutor + SQLite) from charly-installed wrapper scripts, serving an authenticated REST API on :8080." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/pod-airflow:v2026.290.2110` | + +Apache Airflow runs single-node (LocalExecutor + SQLite) from charly-installed wrapper scripts, serving an authenticated REST API on :8080. +The airflow candy installs four /usr/local/bin wrapper scripts that +drive Airflow 3.x under supervisord: airflow-init.sh (one-shot `db +migrate` + binds the SimpleAuthManager admin password to the injected +AIRFLOW_ADMIN_PASSWORD secret) plus airflow-webserver.sh (api-server), +airflow-scheduler.sh, and airflow-dag-processor.sh. At deploy the +three daemons serve the REST API on :8080; notebooks self-author DAGs +into AIRFLOW__CORE__DAGS_FOLDER at runtime. The verifiable artifacts +are the wrapper scripts (build scope) and the live REST API + JWT +issuance (deploy scope). + +## Services + +- `airflow-init` +- `airflow-scheduler` +- `airflow-dag-processor` +- `airflow-webserver` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | mkdir=${HOME}/airflow | +| `run` | mkdir=${HOME}/airflow/dags | +| `run` | mkdir=${HOME}/airflow/logs | +| `run` | mkdir=${HOME}/airflow/plugins | +| `run` | write=/usr/local/bin/airflow-init.sh | +| `run` | write=/usr/local/bin/airflow-webserver.sh | +| `run` | write=/usr/local/bin/airflow-scheduler.sh | +| `run` | write=/usr/local/bin/airflow-dag-processor.sh | +| `check` | the one-shot init wrapper is installed and executable | +| `check` | the api-server wrapper is installed and executable | +| `check` | the scheduler wrapper is installed and executable | +| `check` | the dag-processor wrapper is installed and executable | +| `check` | the running api-server answers /api/v2/version with HTTP 200 | +| `check` | posting the injected admin credentials to /auth/token returns a bearer access_token | +| `check` | command=test -f ${HOME}/airflow/airflow.db | +| `check` | service=airflow-scheduler | +| `check` | service=airflow-dag-processor | +| `check` | service=airflow-webserver | +| `check` | addr=127.0.0.1:${HOST_PORT:8080} | diff --git a/src/content/docs/reference/candy/github-com-opencharly-pod-comfyui-v2026-290-1729/comfyui.md b/src/content/docs/reference/candy/github-com-opencharly-pod-comfyui-v2026-290-1729/comfyui.md new file mode 100644 index 00000000..2cfb4750 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-pod-comfyui-v2026-290-1729/comfyui.md @@ -0,0 +1,41 @@ +--- +title: "comfyui" +description: "GPU image-generation server with ComfyUI + the Manager and model-download tooling baked in Clones ComfyUI to ~/ComfyUI plus the ComfyUI-Manager custom node and the full model directory tree, and installs the aria2 + git-lfs tooling used to fetch model checkpoints." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/pod-comfyui:v2026.290.1729` | + +GPU image-generation server with ComfyUI + the Manager and model-download tooling baked in +Clones ComfyUI to ~/ComfyUI plus the ComfyUI-Manager custom node and +the full model directory tree, and installs the aria2 + git-lfs tooling +used to fetch model checkpoints. A supervisord service runs +`main.py --listen 0.0.0.0` on port 8188. Each piece is verifiable: the +cloned entrypoint and Manager, the model dirs, the download-tooling +packages, and the live /system_stats API on port 8188. + +## Services + +- `comfyui` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | command=git clone --depth 1 https://github.com/comfyanonymous/ComfyUI.git ${HOME}/ComfyUI \|\| true cd ${HOME}/ComfyUI mkdir -p models/{checkpoints,clip,clip_vision,configs,controlnet} mkdir -p models/{diffusers,diffusion_models,embeddings,gligen,hypernetworks,loras} mkdir -p models/{photomaker,style_models,text_encoders,unet,upscale_models,vae,vae_approx} mkdir -p custom_nodes output input user git clone --depth 1 https://github.com/ltdrdata/ComfyUI-Manager.git ${HOME}/ComfyUI/custom_nodes/ComfyUI-Manager \|\| true | +| `check` | the ComfyUI server entrypoint main.py is baked into ~/ComfyUI | +| `check` | the ComfyUI-Manager custom node directory is cloned alongside it | +| `check` | aria2c is installed so model checkpoints can be fetched in parallel | +| `check` | git-lfs is installed for pulling large model repositories | +| `agent-check` | the comfyui supervisord service comes up and serves the image-generation web UI and /system_stats API on port 8188 | +| `check` | file=${HOME}/ComfyUI/models/checkpoints | +| `check` | package=aria2 | +| `check` | file=/usr/bin/git-lfs | +| `check` | service=comfyui | +| `check` | addr=127.0.0.1:${HOST_PORT:8188} | +| `check` | http=http://127.0.0.1:${HOST_PORT:8188}/system_stats | diff --git a/src/content/docs/reference/candy/github-com-opencharly-pod-crabbox-coordinator-v2026-293-1003/crabbox-coordinator.md b/src/content/docs/reference/candy/github-com-opencharly-pod-crabbox-coordinator-v2026-293-1003/crabbox-coordinator.md new file mode 100644 index 00000000..1d2325a0 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-pod-crabbox-coordinator-v2026-293-1003/crabbox-coordinator.md @@ -0,0 +1,55 @@ +--- +title: "crabbox-coordinator" +description: "The Crabbox Node.js/PostgreSQL coordinator (https://github.com/openclaw/crabbox, https://github.com/openclaw/crabbox/tree/main/worker/node) as a supervised service." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/pod-crabbox-coordinator:v2026.293.1003` | + +The Crabbox Node.js/PostgreSQL coordinator (https://github.com/openclaw/crabbox, +https://github.com/openclaw/crabbox/tree/main/worker/node) as a supervised +service. Clones the pinned upstream tag, builds the Node runtime in-image +(npm ci --include=dev + build:node + prune — the same recipe as the upstream +worker/Dockerfile.node incl. the noVNC vendor step; the devDeps are needed +AT BUILD (esbuild), so ci forces them in despite the candy's +NODE_ENV=production runtime env; runtime stays slim via npm prune --omit=dev), and runs +`node dist-node/server.mjs` under supervisord at priority 20 (after the +postgresql service's 10), listening on port 8080 with /v1/health and +/v1/ready container probes. The runtime start wrapper assembles +DATABASE_URL from deploy-provided POSTGRES_* env (supervisord cannot +expand variables), creating the crabbox/crabbox_jobs schemas on startup. +Auth is deploy-time: shared-token (CRABBOX_SHARED_TOKEN + _OWNER) or +GitHub OAuth — the candy ships none by default. This is the LOCAL, +single-replica deployment (upstream flags the Node runtime as newly +shipped; exact-tag pin + in-beds proof, no production-cloud cutover +claims). Coordinator and CLI move in lockstep from one upstream +release: this candy pins v0.79.0, which pairs with the layer-crabbox +CLI 0.79.0 (v0.79.0's coordinator requires non-admin control +clients to reconnect once after the update, upstream #2907). The observable, verifiable effect — the built runtime at a +fixed path, the supervised service, and live /v1/health + /v1/ready +200s backed by a real PostgreSQL — is exactly what the plan block +asserts. + +## Services + +- `crabbox-coordinator` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | clone the pinned upstream coordinator source — annotated tag dereferenced to its peeled commit (git from layer-gh) | +| `run` | install the worker's dependencies INCLUDING dev (esbuild needs them at build; NODE_ENV=production from the candy env would otherwise drop them) | +| `run` | build the Node runtime (dist-node/server.mjs) | +| `run` | prune dev dependencies for the slim runtime | +| `run` | write the runtime start wrapper (assembles DATABASE_URL from deploy env) | +| `check` | the built Node coordinator runtime is present at the fixed path | +| `check` | the coordinator start wrapper is installed and executable | +| `check` | the running coordinator's /v1/health liveness endpoint responds 200 (node runtime container probe) | +| `check` | the running coordinator's /v1/ready readiness endpoint responds 200 | +| `check` | the crabbox-coordinator runs as a supervised service | diff --git a/src/content/docs/reference/candy/github-com-opencharly-pod-jupyter-ml-v2026-290-1836/jupyter-ml.md b/src/content/docs/reference/candy/github-com-opencharly-pod-jupyter-ml-v2026-290-1836/jupyter-ml.md new file mode 100644 index 00000000..71a5b75c --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-pod-jupyter-ml-v2026-290-1836/jupyter-ml.md @@ -0,0 +1,45 @@ +--- +title: "jupyter-ml" +description: "GPU JupyterLab serving notebooks plus a CRDT MCP endpoint, composing the llama.cpp + vLLM/unsloth ML stack." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/pod-jupyter-ml:v2026.290.1836` | + +GPU JupyterLab serving notebooks plus a CRDT MCP endpoint, composing the llama.cpp + vLLM/unsloth ML stack. +A Tier-2 GPU meta-layer that serves JupyterLab on port 8888 from the +/workspace volume under supervisord and exposes a CRDT MCP endpoint at +/mcp for agent-driven notebook editing. It composes the llama-cpp +(llama.cpp CLI + GGUF tools), unsloth (vLLM inference + LoRA +fine-tuning), and jupyter-mcp candies on top of the spaCy NLP model and +the jupyterlab-quarto extension. Every composed piece lands a concrete, +probeable artifact: the llama-cli binary, the vLLM wheel in the pixi +env, the spaCy model, the quarto labextension, and the live notebook + +MCP API — so being wrong is observable, not silent. + +## Services + +- `jupyter-ml` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `check` | the spaCy en_core_web_sm model loads inside the pixi default environment | +| `check` | the jupyterlab-quarto extension is enabled in the labextension registry | +| `check` | the llama.cpp CLI binary is present from the composed llama-cpp candy | +| `check` | the vLLM inference engine wheel is installed in the pixi env from the composed unsloth candy | +| `check` | the workspace volume is mounted for notebooks | +| `check` | the JupyterLab service is running under supervisord | +| `check` | the JupyterLab REST API answers on the published port with a server version | +| `check` | the Jupyter CRDT MCP server responds to a protocol ping | +| `check` | the MCP tool catalog exposes the cell manipulation tools | +| `agent-check` | an agent can create a notebook and drive its cells through the MCP server end to end | +| `check` | command=${HOME}/.pixi/envs/default/bin/python -c "import spacy; spacy.load('en_core_web_sm')" | +| `check` | command=${HOME}/.pixi/envs/default/bin/jupyter labextension list 2>&1 | +| `check` | mcp=call | diff --git a/src/content/docs/reference/candy/github-com-opencharly-pod-marimo-v2026-290-2104/marimo.md b/src/content/docs/reference/candy/github-com-opencharly-pod-marimo-v2026-290-2104/marimo.md new file mode 100644 index 00000000..0abde9ac --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-pod-marimo-v2026-290-2104/marimo.md @@ -0,0 +1,53 @@ +--- +title: "marimo" +description: "marimo reactive notebook + MCP server on port 2718 with GPU OSM analytics, Airflow deps, and the marimo-team skills set for AI agents Installs marimo (a reactive notebook server that also runs as an MCP server via `--mcp` on the same port 2718) plus its data stack into a pixi env at ${HOME}/.pixi/envs/default: GPU-accelerated OSM analytics deps (Polars-GPU/cuDF, geopandas, quackosm), Apache Airflow Python deps (the airflow layer ships no pixi env of its own), and the marimo-team/learn curriculum." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/pod-marimo:v2026.290.2104` | + +marimo reactive notebook + MCP server on port 2718 with GPU OSM analytics, Airflow deps, and the marimo-team skills set for AI agents +Installs marimo (a reactive notebook server that also runs as an MCP +server via `--mcp` on the same port 2718) plus its data stack into a +pixi env at ${HOME}/.pixi/envs/default: GPU-accelerated OSM analytics +deps (Polars-GPU/cuDF, geopandas, quackosm), Apache Airflow Python +deps (the airflow layer ships no pixi env of its own), and the +marimo-team/learn curriculum. The marimo-team/skills set is +unpacked read-only at /opt/marimo-skills (MARIMO_SKILLS_DIR) for AI +agents driving marimo over MCP, and a baked marimo.toml turns +auto_instantiate on so cells run the moment the notebook URL opens. +Every claim below is observable: the pixi-env binaries, the skills +directory, the config line, and — at deploy scope — the live notebook +UI plus the MCP endpoint on /mcp/server. + +## Services + +- `marimo` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | mkdir=/workspace | +| `run` | mkdir=/opt/marimo-skills | +| `run` | download=https://github.com/marimo-team/skills/archive/refs/heads/main.tar.gz | +| `run` | mkdir=${HOME}/.config/marimo | +| `run` | write=${HOME}/.config/marimo/marimo.toml | +| `check` | the marimo notebook+MCP server binary is installed in the pixi env | +| `check` | the Apache Airflow CLI is installed in the same pixi env (the airflow layer ships none of its own) | +| `check` | the marimo-team/skills set is unpacked read-only under MARIMO_SKILLS_DIR | +| `check` | the baked marimo.toml enables auto_instantiate so cells run on page open | +| `agent-check` | a marimo deployment is running with `marimo edit --mcp --mcp-allow-remote` on port 2718 | +| `agent-check` | a client opens the published notebook port and an MCP client pings /mcp/server | +| `agent-check` | the marimo editor UI is served and the MCP endpoint answers protocol requests on the same port | +| `check` | command=${HOME}/.pixi/envs/default/bin/python -c "import marimo, torch, transformers, polars, scipy, altair, plotly, statsmodels, duckdb, sqlalchemy, sqlglot, cvxpy, clarabel, daft, wigglystuff, drawdata, marimo_learn, simpy" | +| `check` | command=${HOME}/.pixi/envs/default/bin/python -c "import geopandas, shapely, fiona, pyproj, quackosm, geoparquet_io, pmtiles, h3, mercantile, folium, contextily, mapclassify, fastmcp, cudf_polars, polars_st, geopolars, geoarrow.pyarrow, geoarrow.pandas, lonboard, freestiler" | +| `check` | addr=127.0.0.1:${HOST_PORT:2718} | +| `check` | http=http://127.0.0.1:${HOST_PORT:2718}/ | +| `check` | mcp=ping | +| `check` | mcp=list-tools | diff --git a/src/content/docs/reference/candy/github-com-opencharly-pod-openwebui-v2026-293-1944/openwebui.md b/src/content/docs/reference/candy/github-com-opencharly-pod-openwebui-v2026-293-1944/openwebui.md new file mode 100644 index 00000000..4eec2b32 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-pod-openwebui-v2026-293-1944/openwebui.md @@ -0,0 +1,42 @@ +--- +title: "openwebui" +description: "Open WebUI LLM chat front-end with an auto-configuring entrypoint, served as a supervised HTTP service on port 8080." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/pod-openwebui:v2026.293.1944` | + +Open WebUI LLM chat front-end with an auto-configuring entrypoint, served as a supervised HTTP service on port 8080. +Installs the Open WebUI server (the `open-webui` PyPI package via pixi) +and copies a bash auto-config entrypoint to +${HOME}/.local/bin/openwebui-entrypoint (mode 0755). A supervised system +service runs that entrypoint, which wires up LLM providers from +env/secrets (OpenRouter, Ollama Cloud, direct OpenAI, local Ollama, MCP +servers, and Jupyter code execution), enforces mandatory admin +credentials (WEBUI_ADMIN_EMAIL + WEBUI_ADMIN_PASSWORD), reads the +auto-generated WEBUI_SECRET_KEY, then exec's `open-webui serve` on port +8080. Every fact below is observable: the installed executable +entrypoint, the running service, the admin email injected into its +environment, and the HTTP 200 the web UI returns on its published port. + +## Services + +- `openwebui` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | mkdir=${HOME}/.local/bin | +| `run` | copy=openwebui-entrypoint | +| `check` | the auto-config entrypoint script is present and executable at ${HOME}/.local/bin/openwebui-entrypoint | +| `check` | the openwebui service is running under the init system | +| `check` | the Open WebUI web interface answers HTTP 200 on the published port | +| `check` | the mandatory admin email is injected into the running service environment | +| `agent-check` | the rendered landing page presents the Open WebUI sign-in experience for the auto-provisioned admin account, ready to start an LLM chat | +| `check` | addr=127.0.0.1:${HOST_PORT:8080} | diff --git a/src/content/docs/reference/candy/github-com-opencharly-pod-unsloth-studio-v2026-290-1913/unsloth-studio.md b/src/content/docs/reference/candy/github-com-opencharly-pod-unsloth-studio-v2026-290-1913/unsloth-studio.md new file mode 100644 index 00000000..1bcbc4e8 --- /dev/null +++ b/src/content/docs/reference/candy/github-com-opencharly-pod-unsloth-studio-v2026-290-1913/unsloth-studio.md @@ -0,0 +1,39 @@ +--- +title: "unsloth-studio" +description: "Unsloth Studio web UI for GPU LLM fine-tuning, backed by a pixi PyTorch/transformers environment and composed llama.cpp GGUF export tools unsloth-studio owns the pixi fine-tuning environment (Python 3.13 + PyTorch/CUDA + transformers + PEFT/TRL) and composes the llama-cpp and unsloth candies, then runs the Unsloth Studio web UI as a supervisord service on port 8888." +--- + + + +| | | +|---|---| +| **Repo** | `box/github.com/opencharly/pod-unsloth-studio:v2026.290.1913` | + +Unsloth Studio web UI for GPU LLM fine-tuning, backed by a pixi PyTorch/transformers environment and composed llama.cpp GGUF export tools +unsloth-studio owns the pixi fine-tuning environment (Python 3.13 + +PyTorch/CUDA + transformers + PEFT/TRL) and composes the llama-cpp and +unsloth candies, then runs the Unsloth Studio web UI as a supervisord +service on port 8888. Every owned artifact lands at a fixed path -- the +pixi interpreter at ~/.pixi/envs/default and the composed llama.cpp CLI +at ~/llama.cpp -- so the environment and the composition's effect are +directly checkable. + +## Services + +- `unsloth-studio` + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | install the Unsloth Studio CLI and bootstrap its runtime venv via the official installer | +| `check` | the Unsloth Studio CLI launcher is installed by the official installer (the `unsloth` console-script is NOT in the pixi env — it comes from install.sh) | +| `check` | the pixi fine-tuning environment provides a Python interpreter at ~/.pixi/envs/default | +| `check` | PyTorch imports successfully inside that environment | +| `check` | the composed llama.cpp CLI binary is present so fine-tuned models can be exported to GGUF | +| `agent-check` | the Unsloth Studio web UI is served on port 8888 and is usable for interactive LLM fine-tuning | +| `check` | command=${HOME}/.pixi/envs/default/bin/python -c "import transformers, peft, trl; print('finetune-stack-ok')" | +| `check` | service=unsloth-studio | +| `check` | addr=127.0.0.1:${HOST_PORT:8888} | diff --git a/src/content/docs/reference/candy/omarchy/omarchy-skills.md b/src/content/docs/reference/candy/omarchy/omarchy-skills.md new file mode 100644 index 00000000..172963e7 --- /dev/null +++ b/src/content/docs/reference/candy/omarchy/omarchy-skills.md @@ -0,0 +1,29 @@ +--- +title: "omarchy-skills" +description: "Skill-prose bundle for the omarchy image family: owns the `omarchy`, `omarchy-cstream` and `omarchy-vm` `skill:` entities (sibling nodes in this file) and carries their bodies under .agents/skills//SKILL.md." +--- + + + +| | | +|---|---| +| **Repo** | `box/omarchy` | + +Skill-prose bundle for the omarchy image family: owns the `omarchy`, `omarchy-cstream` +and `omarchy-vm` `skill:` entities (sibling nodes in this file) and carries their +bodies under .agents/skills//SKILL.md. +It exists because a `skill:` node's owner must be a candy, not an image — an image has +no source directory, so an image-owned node's prose is unreadable and the skill is +absent from the ai.opencharly.skill OCI label (opencharly/sdk#434). +Composed into every image that carries one of those skills; installs the tree at the +uid-1000 account's ~/.agents/skills so a harness in the image reads the same prose the +label carries. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | install the skill tree at the uid-1000 account's Agent-Skills location | +| `check` | every skill body this candy carries is installed under the uid-1000 account's ~/.agents/skills | diff --git a/src/content/docs/reference/candy/ubuntu/github-runner-ubuntu.md b/src/content/docs/reference/candy/ubuntu/github-runner-ubuntu.md new file mode 100644 index 00000000..6d6d8f1e --- /dev/null +++ b/src/content/docs/reference/candy/ubuntu/github-runner-ubuntu.md @@ -0,0 +1,81 @@ +--- +title: "github-runner-ubuntu" +description: "The canonical, co-tenant-safe Ubuntu CI-runner recipe: the Docker daemon and its GC/socket-heal timers, the CI userns and journald settings, and the runner tree plus ONE parameterised registration script." +--- + + + +| | | +|---|---| +| **Repo** | `box/ubuntu` | + +The canonical, co-tenant-safe Ubuntu CI-runner recipe: the Docker daemon and its +GC/socket-heal timers, the CI userns and journald settings, and the runner tree plus +ONE parameterised registration script. Extracted from the kind: vm entity that used +to carry it as cloud-init, so the SAME recipe serves every substrate (decision D1, +opencharly/distro-ubuntu issue 37) — a KubeVirt entity used to have to re-author all +of it. Runner REGISTRATION stays an operator step: a token lives one hour and is +never committed. `charly-register-runners` takes the org, name prefix, labels and +count, so one script serves a single VM or a multi-VM fleet. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | install /etc/systemd/system/docker-ci.service as 0644 | +| `run` | install /usr/local/sbin/charly-docker-sock-heal as 0755 | +| `run` | install /etc/systemd/system/charly-docker-sock-heal.service as 0644 | +| `run` | install /etc/systemd/system/charly-docker-sock-heal.timer as 0644 | +| `run` | install /usr/local/sbin/charly-register-runners as 0755 | +| `run` | install /etc/modules-load.d/charly-ci-netfilter.conf as 0644 | +| `run` | install /etc/sysctl.d/99-charly-ci-netfilter.conf as 0644 | +| `run` | install /usr/local/sbin/charly-docker-store-gc as 0755 | +| `run` | install /etc/systemd/system/charly-docker-store-gc.service as 0644 | +| `run` | install /etc/systemd/system/charly-docker-store-gc.timer as 0644 | +| `run` | install /etc/sysctl.d/99-charly-ci-userns.conf as 0644 | +| `run` | install /etc/systemd/journald.conf.d/charly-ci.conf as 0644 | +| `run` | step 1 — systemctl enable --now qemu-guest-agent | +| `run` | step 2 — install -m 0755 -d /etc/apt/keyrings | +| `run` | step 3 — curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/ke | +| `run` | step 4 — chmod a+r /etc/apt/keyrings/docker.asc | +| `run` | step 5 — printf 'deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https: | +| `run` | step 6 — apt-get update -qq | +| `run` | step 7 — DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --allow-downgrad | +| `run` | step 8 — apt-mark hold docker-ce docker-ce-cli | +| `run` | install the hosted-parity job toolchain at deploy time | +| `run` | step 9 — usermod -aG docker ubuntu | +| `run` | step 9b — usermod -aG kvm ubuntu (nested virtualisation) | +| `run` | step 10 — systemctl disable --now docker.service docker.socket \|\| true | +| `run` | step 11 — systemctl daemon-reload | +| `run` | step 12 — systemctl enable --now docker-ci.service \|\| true | +| `run` | step 13 — ln -sfn /run/docker-ci.sock /var/run/docker.sock | +| `run` | step 14 — systemctl enable --now charly-docker-sock-heal.timer \|\| true | +| `run` | step 15 — sysctl -p /etc/sysctl.d/99-charly-ci-userns.conf | +| `run` | load br_netfilter and apply the netfilter sysctls on this boot | +| `run` | step 16 — systemctl daemon-reload | +| `run` | step 17 — systemctl enable --now charly-docker-store-gc.timer \|\| true | +| `run` | step 18 — systemctl restart systemd-journald \|\| true | +| `run` | step 19 — docker version | +| `run` | step 20 — curl -fsSL -o /tmp/runner.tgz https://github.com/actions/runner/releas | +| `run` | step 21 — install -d -o ubuntu -g ubuntu -m 0755 /home/ubuntu/actions-runner-bas | +| `run` | step 22 — tar xzf /tmp/runner.tgz -C /home/ubuntu/actions-runner-base && chown - | +| `run` | create the shared Go cache directories | +| `run` | write the runner .env with the shared Go cache paths | +| `run` | step 23 — if ! swapon --show=NAME \| grep -q '^/swapfile$'; then fallocate -l 8G | +| `run` | step 24 — grep -q '^/swapfile' /etc/fstab \|\| echo '/swapfile none swap sw 0 0' > | +| `check` | the co-tenant CI docker daemon is listening on its own socket | +| `check` | the CI userns sysctl is applied on the guest | +| `check` | the Actions runner agent binary is installed and executable | +| `check` | the runner .env points Go at the VM's shared build/module cache | +| `check` | the runner tree carries NO DOCKER_HOST override, so jobs see the default socket | +| `check` | the one registration script is installed, executable and self-describing | +| `check` | node is installed and reports its version | +| `check` | the gh CLI is installed and reports its version | +| `check` | pip3 and the archive tools are present | +| `check` | the Playwright Chromium runtime packages are installed | +| `check` | ruby is installed for the Scripts job's live smokes | +| `check` | skopeo is installed and reports its version | +| `check` | the runner user can open /dev/kvm when the CPU exposes virtualisation | +| `check` | br_netfilter is loaded and bridge netfilter is enabled | diff --git a/src/content/docs/reference/candy/ubuntu/ubuntu-skills.md b/src/content/docs/reference/candy/ubuntu/ubuntu-skills.md new file mode 100644 index 00000000..98b8429b --- /dev/null +++ b/src/content/docs/reference/candy/ubuntu/ubuntu-skills.md @@ -0,0 +1,29 @@ +--- +title: "ubuntu-skills" +description: "Skill-prose bundle for the ubuntu image family: owns the `ubuntu`, `ubuntu-builder`, `ubuntu-coder`, `ubuntu-debootstrap-builder`, `ubuntu-debootstrap` `skill:` entities (sibling nodes in this file) and carries their bodies under .agents/skills//SKILL.md." +--- + + + +| | | +|---|---| +| **Repo** | `box/ubuntu` | + +Skill-prose bundle for the ubuntu image family: owns the `ubuntu`, `ubuntu-builder`, `ubuntu-coder`, `ubuntu-debootstrap-builder`, `ubuntu-debootstrap` `skill:` +entities (sibling nodes in this file) and carries their bodies under +.agents/skills//SKILL.md. +It exists because a `skill:` node's owner must be a candy, not an image — an image has +no source directory, so an image-owned node's prose is unreadable and the skill is +absent from the ai.opencharly.skill OCI label (opencharly/sdk#434). +Composed into every image that carries one of those skills; installs the tree at the +uid-1000 account's ~/.agents/skills so a harness in the image reads the same prose the +label carries. + +## Acceptance plan + +This candy's `plan:` — the runnable spec `charly check` executes against a live deployment. `check:` steps are idempotent probes; `run:` steps change state. + +| Intent | Step | +|---|---| +| `run` | install the skill tree at the uid-1000 account's Agent-Skills location | +| `check` | every skill body this candy carries is installed under the uid-1000 account's ~/.agents/skills | diff --git a/src/content/docs/reference/cli/build-box.md b/src/content/docs/reference/cli/build-box.md index f5b5af8f..a1833d0c 100644 --- a/src/content/docs/reference/cli/build-box.md +++ b/src/content/docs/reference/cli/build-box.md @@ -7,7 +7,7 @@ description: "The build:box command word, served by the plugin-box plugin candy. | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `build:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/cli/check.md b/src/content/docs/reference/cli/check.md index 3a0f2267..ce2ba290 100644 --- a/src/content/docs/reference/cli/check.md +++ b/src/content/docs/reference/cli/check.md @@ -10,7 +10,7 @@ description: "The check command word, served by 2 plugin candies: plugin-check a | **plugin-check — Served by** | [plugin-check](/reference/plugin/github-com-opencharly-plugin-check-v2026-242-2127/plugin-check/) | | **plugin-check — Placement** | compiled-in (in-process) | | **plugin-check — Version** | `2026.242.2345` | -| **plugin-check — Served by** | [plugin-check](/reference/plugin/github-com-opencharly-plugin-check-v2026-287-1745/plugin-check/) | +| **plugin-check — Served by** | [plugin-check](/reference/plugin/github-com-opencharly-plugin-check-v2026-298-0205/plugin-check/) | | **plugin-check — Placement** | compiled-in (in-process) | `check` is a command word served by 2 plugin candies — `plugin-check` and `plugin-check` — at different points in the command tree. Both are real invocations; `charly --help` prints which is which. diff --git a/src/content/docs/reference/cli/feature-box.md b/src/content/docs/reference/cli/feature-box.md index 16670bee..95a90e8e 100644 --- a/src/content/docs/reference/cli/feature-box.md +++ b/src/content/docs/reference/cli/feature-box.md @@ -7,7 +7,7 @@ description: "The feature:box command word, served by the plugin-box plugin cand | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `feature:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/cli/generate-box.md b/src/content/docs/reference/cli/generate-box.md index 84cf0116..15c3d538 100644 --- a/src/content/docs/reference/cli/generate-box.md +++ b/src/content/docs/reference/cli/generate-box.md @@ -7,7 +7,7 @@ description: "The generate:box command word, served by the plugin-box plugin can | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `generate:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/cli/inspect-box.md b/src/content/docs/reference/cli/inspect-box.md index d744d4c4..10f38bf8 100644 --- a/src/content/docs/reference/cli/inspect-box.md +++ b/src/content/docs/reference/cli/inspect-box.md @@ -7,7 +7,7 @@ description: "The inspect:box command word, served by the plugin-box plugin cand | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `inspect:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/cli/labels-box.md b/src/content/docs/reference/cli/labels-box.md index 46c25b37..da1b6a9a 100644 --- a/src/content/docs/reference/cli/labels-box.md +++ b/src/content/docs/reference/cli/labels-box.md @@ -7,7 +7,7 @@ description: "The labels:box command word, served by the plugin-box plugin candy | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `labels:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/cli/list-box.md b/src/content/docs/reference/cli/list-box.md index 5ea27044..a9d951fc 100644 --- a/src/content/docs/reference/cli/list-box.md +++ b/src/content/docs/reference/cli/list-box.md @@ -7,7 +7,7 @@ description: "The list:box command word, served by the plugin-box plugin candy." | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `list:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/cli/load-box.md b/src/content/docs/reference/cli/load-box.md index 645dab7d..f154c288 100644 --- a/src/content/docs/reference/cli/load-box.md +++ b/src/content/docs/reference/cli/load-box.md @@ -7,7 +7,7 @@ description: "The load:box command word, served by the plugin-box plugin candy." | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `load:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/cli/merge-box.md b/src/content/docs/reference/cli/merge-box.md index 7bd15c47..b1203fc1 100644 --- a/src/content/docs/reference/cli/merge-box.md +++ b/src/content/docs/reference/cli/merge-box.md @@ -7,7 +7,7 @@ description: "The merge:box command word, served by the plugin-box plugin candy. | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `merge:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/cli/migrate.md b/src/content/docs/reference/cli/migrate.md index 2875a61e..2eb78ef4 100644 --- a/src/content/docs/reference/cli/migrate.md +++ b/src/content/docs/reference/cli/migrate.md @@ -10,7 +10,7 @@ description: "The migrate command word, served by 2 plugin candies: plugin-migra | **plugin-migrate — Served by** | [plugin-migrate](/reference/plugin/github-com-opencharly-plugin-migrate-v2026-242-0530/plugin-migrate/) | | **plugin-migrate — Placement** | compiled-in (in-process) | | **plugin-migrate — Version** | `2026.186.0100` | -| **plugin-migrate — Served by** | [plugin-migrate](/reference/plugin/github-com-opencharly-plugin-migrate-v2026-280-2238/plugin-migrate/) | +| **plugin-migrate — Served by** | [plugin-migrate](/reference/plugin/github-com-opencharly-plugin-migrate-v2026-295-1526/plugin-migrate/) | | **plugin-migrate — Placement** | compiled-in (in-process) | `migrate` is a command word served by 2 plugin candies — `plugin-migrate` and `plugin-migrate` — at different points in the command tree. Both are real invocations; `charly --help` prints which is which. diff --git a/src/content/docs/reference/cli/new-box.md b/src/content/docs/reference/cli/new-box.md index 4d13f4ab..423b60ea 100644 --- a/src/content/docs/reference/cli/new-box.md +++ b/src/content/docs/reference/cli/new-box.md @@ -7,7 +7,7 @@ description: "The new:box command word, served by the plugin-box plugin candy." | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `new:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/cli/ollama.md b/src/content/docs/reference/cli/ollama.md index 1e9057f7..76e41277 100644 --- a/src/content/docs/reference/cli/ollama.md +++ b/src/content/docs/reference/cli/ollama.md @@ -1,6 +1,6 @@ --- title: "ollama" -description: "The ollama command word, served by 3 plugin candies: plugin-ollama and plugin-ollama and plugin-ollama." +description: "The ollama command word, served by 4 plugin candies: plugin-ollama and plugin-ollama and plugin-ollama and plugin-ollama." --- @@ -15,8 +15,39 @@ description: "The ollama command word, served by 3 plugin candies: plugin-ollama | **plugin-ollama — Version** | `2026.229.1013` | | **plugin-ollama — Served by** | [plugin-ollama](/reference/plugin/github-com-opencharly-plugin-ollama-v2026-272-0330/plugin-ollama/) | | **plugin-ollama — Placement** | compiled-in (in-process) | +| **plugin-ollama — Served by** | [plugin-ollama](/reference/plugin/github-com-opencharly-plugin-ollama-v2026-289-0014/plugin-ollama/) | +| **plugin-ollama — Placement** | compiled-in (in-process) | + +`ollama` is a command word served by 4 plugin candies — `plugin-ollama` and `plugin-ollama` and `plugin-ollama` and `plugin-ollama` — at different points in the command tree. Both are real invocations; `charly --help` prints which is which. + +## About `plugin-ollama`, which serves it + +COMPILED-IN charly COMMAND-class plugin (command:ollama) OWNING the entire +`charly ollama` CLI — the host-side management surface for a DEPLOYED Ollama +server: list / ps / pull / rm / show / cp / create / push / run / stop / +version. The plugin owns the ENTIRE logic: the hand-rolled subcommand grammar +AND the Ollama HTTP API calls, built on the official upstream Go client +(github.com/ollama/ollama/api, pinned in the candy's own go.mod). There is NO +core ollama logic and NO HostBuild seam. + +The command talks to the server over plain HTTP, so it is fully self-contained +and works IDENTICALLY compiled-in OR out-of-process: listed in charly.yml +compiled_plugins it registers in-proc and the host dispatches it through +dispatchInProcCommand → Invoke(OpRun) → runOllamaCLI; the out-of-process +placement fork/execs cmd/serve → CliMain running the SAME runOllamaCLI. +Endpoint resolution is deliberately lightweight: --server flag > OLLAMA_HOST env +> http://127.0.0.1:11434. -`ollama` is a command word served by 3 plugin candies — `plugin-ollama` and `plugin-ollama` and `plugin-ollama` — at different points in the command tree. Both are real invocations; `charly --help` prints which is which. +This is a sibling of the ollama CANDY (candy/ollama — which deploys the +server) and of the candy's host shell `alias: ollama` (which execs the +upstream CLI inside the container): three disjoint surfaces. Full Modelfile +authoring stays with the upstream CLI; `charly ollama create` covers the +lightweight --from form. + +The R10 witness is the disposable check-ollama-pod bed (box/fedora): it deploys +the ollama image and runs `charly ollama list|version --server +http://127.0.0.1:${HOST_PORT:11434}` host-side against the live server, plus +the candy's baked checks. ## About `plugin-ollama`, which serves it diff --git a/src/content/docs/reference/cli/pull-box.md b/src/content/docs/reference/cli/pull-box.md index 10136e12..0a155813 100644 --- a/src/content/docs/reference/cli/pull-box.md +++ b/src/content/docs/reference/cli/pull-box.md @@ -7,7 +7,7 @@ description: "The pull:box command word, served by the plugin-box plugin candy." | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `pull:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/cli/reconcile-box.md b/src/content/docs/reference/cli/reconcile-box.md index b9c951c5..6eaa0f18 100644 --- a/src/content/docs/reference/cli/reconcile-box.md +++ b/src/content/docs/reference/cli/reconcile-box.md @@ -7,7 +7,7 @@ description: "The reconcile:box command word, served by the plugin-box plugin ca | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `reconcile:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/cli/task.md b/src/content/docs/reference/cli/task.md index 62ee5ac2..d35b7c18 100644 --- a/src/content/docs/reference/cli/task.md +++ b/src/content/docs/reference/cli/task.md @@ -9,7 +9,7 @@ description: "The task command word, served by 2 plugin candies: plugin-task and |---|---| | **plugin-task — Served by** | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-276-1230/plugin-task/) | | **plugin-task — Placement** | compiled-in (in-process) | -| **plugin-task — Served by** | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task/) | +| **plugin-task — Served by** | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task/) | | **plugin-task — Placement** | compiled-in (in-process) | `task` is a command word served by 2 plugin candies — `plugin-task` and `plugin-task` — at different points in the command tree. Both are real invocations; `charly --help` prints which is which. @@ -67,7 +67,7 @@ which a self-contained plugin schema cannot carry). Five GENERIC, domain-neutral MAINTENANCE verbs replace repository shell scripts, each parameterized by the repo's own data (paths/pairs/pins) so the plugin stays reusable by any repository: `verb:git-submodules` (status/bump/ -verify `.gitmodules` pins, incl. the policy-B comparison of a repo's pins +verify `.gitmodules` pins, incl. the EDGE comparison of a repo's pins against a pinned checkout's gitlinks), `verb:file-parity` (check/sync that paired files are byte-identical), `verb:splice-region` (splice a marked region from a fragment into a target), `verb:module-pins` (adopt a diff --git a/src/content/docs/reference/cli/validate-box.md b/src/content/docs/reference/cli/validate-box.md index 46fa6e2a..55ff06a6 100644 --- a/src/content/docs/reference/cli/validate-box.md +++ b/src/content/docs/reference/cli/validate-box.md @@ -7,7 +7,7 @@ description: "The validate:box command word, served by the plugin-box plugin can | | | |---|---| -| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| **Served by** | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | **Placement** | compiled-in (in-process) | `validate:box` is a command word served by the `plugin-box` plugin candy. This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. diff --git a/src/content/docs/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box.md b/src/content/docs/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box.md similarity index 98% rename from src/content/docs/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box.md rename to src/content/docs/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box.md index 42dc5139..ba150df2 100644 --- a/src/content/docs/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box.md +++ b/src/content/docs/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box.md @@ -102,4 +102,4 @@ The CUE schema below is the authoritative grammar for this plugin's input. It is --- -See also the [candy reference](/reference/candy/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) for this candy's install surface. +See also the [candy reference](/reference/candy/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) for this candy's install surface. diff --git a/src/content/docs/reference/plugin/github-com-opencharly-plugin-build-v2026-287-2220/plugin-build.md b/src/content/docs/reference/plugin/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build.md similarity index 91% rename from src/content/docs/reference/plugin/github-com-opencharly-plugin-build-v2026-287-2220/plugin-build.md rename to src/content/docs/reference/plugin/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build.md index 20f15a06..0f58ef12 100644 --- a/src/content/docs/reference/plugin/github-com-opencharly-plugin-build-v2026-287-2220/plugin-build.md +++ b/src/content/docs/reference/plugin/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build.md @@ -35,9 +35,11 @@ NewGenerator this candy used to call over HostBuild is DELETED, #55 step3 3-II), the host only for what a sdk-only candy structurally cannot do (the bootstrap-delicate local scan, the git fetch, the build-time plugin connect, the host-fs prep) over a small `buildengine-*` HostBuild leg family; the layer MERGE crosses to verb:oci via -InvokeProvider (no HostBuild("merge") seam). The candy then runs podman directly — -building each image (Containerfile piped over stdin), gating the inline merge on the -box's MergeAuto, and pushing (podman) after merge; build:generate renders the .build/ +InvokeProvider (no HostBuild("merge") seam). Each stage is built with BuildKit and its +image is STORED IN THE CONFIGURED CONTAINER BACKEND (the SDK `LoadExport`), then pushed +to the LOCAL CHARLY OCI REGISTRY under the same FullTag, which the daemon mirrors +`ghcr.io/opencharly` to — so the next stage's `FROM` resolves an internal base locally, +never against the upstream registry. build:generate renders the .build/ Containerfile tree in its own code (via sdk/deploykit, #67) and returns the written paths (no podman, no merge); build:ensure resolves a project-authored image identifier against charly.yml PLUGIN-SIDE (loaderkit.LoadUnified via the K1 loader reverse legs — @@ -91,4 +93,4 @@ The CUE schema below is the authoritative grammar for this plugin's input. It is --- -See also the [candy reference](/reference/candy/github-com-opencharly-plugin-build-v2026-287-2220/plugin-build/) for this candy's install surface. +See also the [candy reference](/reference/candy/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build/) for this candy's install surface. diff --git a/src/content/docs/reference/plugin/github-com-opencharly-plugin-check-v2026-287-1745/plugin-check.md b/src/content/docs/reference/plugin/github-com-opencharly-plugin-check-v2026-298-0205/plugin-check.md similarity index 98% rename from src/content/docs/reference/plugin/github-com-opencharly-plugin-check-v2026-287-1745/plugin-check.md rename to src/content/docs/reference/plugin/github-com-opencharly-plugin-check-v2026-298-0205/plugin-check.md index 971bb1c1..f29ef2b0 100644 --- a/src/content/docs/reference/plugin/github-com-opencharly-plugin-check-v2026-287-1745/plugin-check.md +++ b/src/content/docs/reference/plugin/github-com-opencharly-plugin-check-v2026-298-0205/plugin-check.md @@ -105,4 +105,4 @@ The CUE schema below is the authoritative grammar for this plugin's input. It is --- -See also the [candy reference](/reference/candy/github-com-opencharly-plugin-check-v2026-287-1745/plugin-check/) for this candy's install surface. +See also the [candy reference](/reference/candy/github-com-opencharly-plugin-check-v2026-298-0205/plugin-check/) for this candy's install surface. diff --git a/src/content/docs/reference/plugin/github-com-opencharly-plugin-crabbox-v2026-293-1011/plugin-crabbox.md b/src/content/docs/reference/plugin/github-com-opencharly-plugin-crabbox-v2026-293-1011/plugin-crabbox.md new file mode 100644 index 00000000..6bda4f95 --- /dev/null +++ b/src/content/docs/reference/plugin/github-com-opencharly-plugin-crabbox-v2026-293-1011/plugin-crabbox.md @@ -0,0 +1,133 @@ +--- +title: "plugin-crabbox" +description: "OUT-OF-TREE charly plugin serving the `crabbox` check verb — a standalone Go module (go.mod + main.go) that probes the Crabbox CLI and its optional local coordinator, served OUT-OF-PROCESS over go-plugin gRPC via the charly plugin SDK (github.com/opencharly/sdk)." +--- + + + +| | | +|---|---| +| **Placement** | runtime (out-of-process over gRPC) | +| **Source** | `github.com/opencharly/plugin-crabbox/candy/plugin-crabbox` | +| **Candy** | `plugin-crabbox` | + +This plugin is **not** listed in `charly/charly.yml`'s `compiled_plugins:`. It is not part of the shipped binary: charly builds and loads it out-of-process over gRPC when a plan references one of its words (the coexist path). + +## Providers + +The reserved words this plugin serves: + +- **`crabbox`** — verb class + +## What it does + +OUT-OF-TREE charly plugin serving the `crabbox` check verb — a standalone +Go module (go.mod + main.go) that probes the Crabbox CLI and its optional +local coordinator, served OUT-OF-PROCESS over go-plugin gRPC via the charly +plugin SDK (github.com/opencharly/sdk). charly's loader fetches this candy's +repo, go-builds the provider binary on the HOST, and serves it via +LocalTransport — so an authored `crabbox:` step dispatches through the +provider registry exactly like a built-in. + +The verb has THREE method classes. In-venue CLI methods (version/providers/ +config/doctor — credential-free — and leases/usage/events/logs — +broker-backed, requiring a `crabbox login` in the venue) run the `crabbox` +binary INSIDE the venue over the reverse channel (cc.Exec). Coordinator +HTTP probe methods (health/ready) hit the Node.js/PostgreSQL coordinator's +/v1/health and /v1/ready endpoints — the container-probe surface the +coordinator exposes — from the charly host against the resolved endpoint +(cc.ResolveEndpoint + cc.HTTPDo, one authored step works unchanged against a +pod's published port and a VM's forwarded one). All methods are read-only; +there are no mutating methods in this first cut. + +It is NOT a re-skin of the generic `command:`/`http:` verbs: this plugin +exists for what those structurally cannot do — ENDPOINT RESOLUTION +(cc.ResolveEndpoint for the coordinator probes) and DOMAIN SEMANTICS +(methods map to the crabbox CLI's real surface and return real verdicts, +with `json_path:` to assert one field; the in-venue CLI methods reach the +binary where it is installed, which `http:` cannot). + +The R10 consumers are the crabbox-bearing beds (check-crabbox-pod and +check-crabbox-e2e-pod) whose checks compose this plugin alongside the +`crabbox` CLI candy from opencharly/layer-crabbox and the coordinator candy +from opencharly/pod-crabbox. + +## Parameter schema + +The CUE schema below is the authoritative grammar for this plugin's input. It is the same single source that generates the plugin's Go parameter types and answers the runtime `Describe` RPC, so this page cannot disagree with either. + +### `schema/crabbox.cue` + +```cue +// The `crabbox` plugin's OWN CUE schema — the typed plugin_input for the +// `crabbox` check verb, which probes the Crabbox CLI and its optional local +// Node.js/PostgreSQL coordinator: in-venue CLI methods (credential-free +// version/providers/config/doctor; broker-backed leases/usage/events/logs) and +// coordinator HTTP probe methods (health/ready). +// +// SELF-CONTAINED by contract: it references NO base def, so it compiles standalone +// (both `cue exp gengotypes` and the host's load-gate compile) AND splices onto the +// base as `base ++ plugin`. +// +// Single source, used two ways: +// 1. GENERATE ../params/cue_types_gen.go via `cue exp gengotypes`, so the provider +// decodes plugin_input into a TYPED struct rather than a hand-parsed map. +// 2. VALIDATE authored input AT RUNTIME — served over Describe, spliced by the host, +// and every authored `crabbox:` step's plugin_input checked against #CrabboxInput. +#CrabboxInput: { + // method — the operation (also the scalar-sugar primary, so `crabbox: version` + // desugars to {method: "version"}). + // + // In-venue CLI methods (version/providers/config/doctor/leases/usage/events/logs) + // run inside the venue where the `crabbox` binary is installed; coordinator HTTP + // probe methods (health/ready) are issued from the charly HOST against the + // resolved coordinator endpoint. All are read-only — there are no mutating + // methods in this first cut. + method: "version" | "providers" | "config" | "doctor" | "health" | "ready" | "leases" | "usage" | "events" | "logs" + + // port — the coordinator port to probe for health/ready. Default 8080 (the + // crabbox-coordinator candy's published port). + port?: int & >0 & <65536 + + // timeout — the HTTP probe timeout. Default 10s. + timeout?: string & =~"^[0-9]+s$" + + // json_path — a dotted path into the JSON response; when set, the verb's stdout is + // the value at that path rather than the whole document, so a `stdout:` matcher can + // assert one field without pattern-matching a blob. + json_path?: string @go(JSONPath) + + // run_id — run identifier required by the events/logs methods. + // + // @go names the generated field: the committed params file carried a hand-shaped + // `RunID` while the generator's default for `run_id` is `Run_id`, i.e. the generated + // file had drifted from this schema and no gate here caught it (this repo runs + // `charly candy params --check` nowhere). The directive is the schema's own mechanism — + // the same one `json_path` uses — so the regeneration is a no-op from here on. + run_id?: string @go(RunID) + + // provider — the provider to select for the methods whose CLI command DEFINES the + // `--provider ` flag. MEASURED at the pinned v0.79.0: `doctor` and `leases` + // (which runs `crabbox list`) accept it; `usage` and `providers` reject it + // ("flag provided but not defined: -provider"), so it is passed through only where the + // CLI defines it. Unset = the CLI's own configured/ambient selection, which is what the + // previous surface always got. + provider?: string + + // target — the provider's target platform, passed through as the CLI's `--target ` flag. + // The firecracker provider is Linux-only, so `target: linux` is the meaningful value there. + target?: string @go(Target) + + // firecracker — the provider's own configuration keys, passed through as the CLI's + // `--firecracker- ` flags. Measured from the provider's documented Configuration + // section, which shows `firecracker:` carrying at least `binary:`. The block is deliberately OPEN + // because the provider's key set is its own surface: a closed copy here would drift the moment + // upstream adds a key (R2). + firecracker?: {...} @go(Firecracker) +} +``` + + +--- + +See also the [candy reference](/reference/candy/github-com-opencharly-plugin-crabbox-v2026-293-1011/plugin-crabbox/) for this candy's install surface. diff --git a/src/content/docs/reference/plugin/github-com-opencharly-plugin-migrate-v2026-280-2238/plugin-migrate.md b/src/content/docs/reference/plugin/github-com-opencharly-plugin-migrate-v2026-295-1526/plugin-migrate.md similarity index 89% rename from src/content/docs/reference/plugin/github-com-opencharly-plugin-migrate-v2026-280-2238/plugin-migrate.md rename to src/content/docs/reference/plugin/github-com-opencharly-plugin-migrate-v2026-295-1526/plugin-migrate.md index be4c3d13..a64c5a5a 100644 --- a/src/content/docs/reference/plugin/github-com-opencharly-plugin-migrate-v2026-280-2238/plugin-migrate.md +++ b/src/content/docs/reference/plugin/github-com-opencharly-plugin-migrate-v2026-295-1526/plugin-migrate.md @@ -100,7 +100,16 @@ The CUE schema below is the authoritative grammar for this plugin's input. It is // declarative ops OR a named Go escape-hatch hook. #Migration: { name: string // short label for --dry-run / progress - touches_host?: bool | *false // also rewrite the per-host overlay? + touches_host?: bool | *false // also rewrite a per-host file? + // host_config selects WHICH per-host file a touches_host step rewrites. The two + // files are DIFFERENT types and must never be conflated: + // overlay — ~/.config/charly/charly.yml (spec.DeployConfig: deploy/sidecar/ + // cache/ledger/system; no engine field); + // runtime_config — ~/.config/charly/config.yml (hostenv.RuntimeConfig: engine/ + // run_mode/bind_address/vm/…). + // Only meaningful with touches_host and ignored otherwise. Default overlay keeps + // every pre-existing host step on the file it was authored against. + host_config?: *"overlay" | "runtime_config" ops?: [...#MigrationOp] // declarative ops, applied in order (mutually exclusive with apply) apply?: string // named Go hook for a structural reshape (mutually exclusive with ops) } @go(-) @@ -127,4 +136,4 @@ The CUE schema below is the authoritative grammar for this plugin's input. It is --- -See also the [candy reference](/reference/candy/github-com-opencharly-plugin-migrate-v2026-280-2238/plugin-migrate/) for this candy's install surface. +See also the [candy reference](/reference/candy/github-com-opencharly-plugin-migrate-v2026-295-1526/plugin-migrate/) for this candy's install surface. diff --git a/src/content/docs/reference/plugin/github-com-opencharly-plugin-ollama-v2026-289-0014/plugin-ollama.md b/src/content/docs/reference/plugin/github-com-opencharly-plugin-ollama-v2026-289-0014/plugin-ollama.md new file mode 100644 index 00000000..85a09374 --- /dev/null +++ b/src/content/docs/reference/plugin/github-com-opencharly-plugin-ollama-v2026-289-0014/plugin-ollama.md @@ -0,0 +1,89 @@ +--- +title: "plugin-ollama" +description: "COMPILED-IN charly COMMAND-class plugin (command:ollama) OWNING the entire `charly ollama` CLI — the host-side management surface for a DEPLOYED Ollama server: list / ps / pull / rm / show / cp / create / push / run / stop / version." +--- + + + +| | | +|---|---| +| **Placement** | compiled-in (in-process) | +| **Source** | `github.com/opencharly/plugin-ollama/candy/plugin-ollama` | +| **Candy** | `plugin-ollama` | + +This plugin is listed in `charly/charly.yml`'s `compiled_plugins:`, so its providers are compiled into the `charly` binary and register in-process. + +## Providers + +The reserved words this plugin serves: + +- **`ollama`** — command class + +## What it does + +COMPILED-IN charly COMMAND-class plugin (command:ollama) OWNING the entire +`charly ollama` CLI — the host-side management surface for a DEPLOYED Ollama +server: list / ps / pull / rm / show / cp / create / push / run / stop / +version. The plugin owns the ENTIRE logic: the hand-rolled subcommand grammar +AND the Ollama HTTP API calls, built on the official upstream Go client +(github.com/ollama/ollama/api, pinned in the candy's own go.mod). There is NO +core ollama logic and NO HostBuild seam. + +The command talks to the server over plain HTTP, so it is fully self-contained +and works IDENTICALLY compiled-in OR out-of-process: listed in charly.yml +compiled_plugins it registers in-proc and the host dispatches it through +dispatchInProcCommand → Invoke(OpRun) → runOllamaCLI; the out-of-process +placement fork/execs cmd/serve → CliMain running the SAME runOllamaCLI. +Endpoint resolution is deliberately lightweight: --server flag > OLLAMA_HOST env +> http://127.0.0.1:11434. + +This is a sibling of the ollama CANDY (candy/ollama — which deploys the +server) and of the candy's host shell `alias: ollama` (which execs the +upstream CLI inside the container): three disjoint surfaces. Full Modelfile +authoring stays with the upstream CLI; `charly ollama create` covers the +lightweight --from form. + +The R10 witness is the disposable check-ollama-pod bed (box/fedora): it deploys +the ollama image and runs `charly ollama list|version --server +http://127.0.0.1:${HOST_PORT:11434}` host-side against the live server, plus +the candy's baked checks. + +## Parameter schema + +The CUE schema below is the authoritative grammar for this plugin's input. It is the same single source that generates the plugin's Go parameter types and answers the runtime `Describe` RPC, so this page cannot disagree with either. + +### `schema/ollama.cue` + +```cue +// plugin-ollama's OWN self-contained CUE schema — the SINGLE SOURCE for this plugin's +// served declaration surface (there is no schema-less plugin: every plugin ships a +// non-empty schema over Describe). +// +// SELF-CONTAINED and PACKAGE-LESS: it references no base def and carries no package +// clause, so it compiles STANDALONE — the property the SDK's serve-side compile needs +// and the property that lets the host splice `base ++ plugin` at the load gate +// (registerPluginUnitSchema); a self-contained schema that will not splice is a LOUD +// load failure. +// +// NO GO CONSUMER: the plugin declares no typed `plugin_input` (its authored input is +// its pass-through CLI grammar), so this schema generates NO `params` package and has +// NO `cue exp gengotypes` artifact — it is the SERVED documentation/config surface, +// not a code-generation source. +// +// It DOCUMENTS the `command: ollama` contract and the endpoint/config surface the CLI reads (`--server` flag > `OLLAMA_HOST` env > the declared default). +#OllamaPlugin: { + // The command word the plugin serves. + command: "ollama" + + // What the command does, in one line (the public-docs surface). + contract: string & !="" + + // Endpoint resolution: --server flag > OLLAMA_HOST env > this default. + default_endpoint: "http://127.0.0.1:11434" +} +``` + + +--- + +See also the [candy reference](/reference/candy/github-com-opencharly-plugin-ollama-v2026-289-0014/plugin-ollama/) for this candy's install surface. diff --git a/src/content/docs/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task.md b/src/content/docs/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task.md similarity index 79% rename from src/content/docs/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task.md rename to src/content/docs/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task.md index d245150f..30fd2096 100644 --- a/src/content/docs/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task.md +++ b/src/content/docs/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task.md @@ -45,7 +45,7 @@ which a self-contained plugin schema cannot carry). Five GENERIC, domain-neutral MAINTENANCE verbs replace repository shell scripts, each parameterized by the repo's own data (paths/pairs/pins) so the plugin stays reusable by any repository: `verb:git-submodules` (status/bump/ -verify `.gitmodules` pins, incl. the policy-B comparison of a repo's pins +verify `.gitmodules` pins, incl. the EDGE comparison of a repo's pins against a pinned checkout's gitlinks), `verb:file-parity` (check/sync that paired files are byte-identical), `verb:splice-region` (splice a marked region from a fragment into a target), `verb:module-pins` (adopt a @@ -97,16 +97,45 @@ The CUE schema below is the authoritative grammar for this plugin's input. It is // #GitSubmodulesInput drives `.gitmodules` pin maintenance. #GitSubmodulesInput: { - // mode: status lists; bump stages new gitlinks; verify asserts. - mode: "status" | "bump" | "verify" + // mode: status lists; bump stages new gitlinks; verify asserts CONSISTENCY — + // that every checkout matches the gitlink the index records. currency asks the + // OTHER question, which needs no checkout at all: whether each recorded pin is + // the value its owning repo actually serves (a green verify is not a currency + // claim; it passes on a tree whose submodules are all behind their remotes). + mode: "status" | "bump" | "verify" | "currency" // pinned_from is a checkout path whose gitlinks are authoritative for the // entries named in pin_map (e.g. "charly"). Empty => no pinned set. pinned_from?: string @go(PinnedFrom) // pin_map maps a submodule PATH in this repo to its twin PATH in pinned_from. // On bump, every submodule NOT in pin_map rolls to its own default-branch HEAD. pin_map?: {[string]: string} @go(PinMap) + // intent declares WHY each pin holds the value it does, so CURRENCY is + // answerable rather than assumed. Two shapes, and they are not interchangeable: + // + // "upstream:" a LEAF — the value is the owning repo's OWN ref, read + // from the remote; no local state enters the answer. + // "derived-from:" an EDGE — the value is 's recorded gitlink. + // + // An entry in pin_map IS an edge (derived-from:pinned_from) and needs no intent + // entry. An edge may NOT point at another edge (depth <= 2): the graph is + // acyclic BY CONSTRUCTION, not by a validation that can be skipped. A path whose + // intent is absent AND which carries no `branch=` in .gitmodules is "unpinned" — + // reported as such, never silently treated as a leaf. + intent?: {[string]: string} @go(Intent) // skip lists submodule paths the verb must not touch. skip?: [...string] + // stale_after is the OWNER's bound on its OWN bookkeeping, and it is opt-in: unset + // => the knob is off and the currency verdict is the structural one alone. + // + // It is a duration ("168h"). A pin that is not current AND that this repo has not + // advanced for LONGER than this bound is STALE, and a stale pin FAILS. + // + // The bound is on the AGE of this repo's last advance of that path — NOT on the + // pin's distance from the ref it names. The distance is CHURN: a busy upstream is + // behind between every wave, so a gate that failed on the distance would be + // permanently red on a healthy tree, and a permanently red gate trains every reader + // to ignore it. The age is NEGLECT, and neglect is the defect this bounds. + stale_after?: string @go(StaleAfter) } // #FileParityInput asserts (or syncs) that paired files are byte-identical. @@ -176,4 +205,4 @@ The CUE schema below is the authoritative grammar for this plugin's input. It is --- -See also the [candy reference](/reference/candy/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task/) for this candy's install surface. +See also the [candy reference](/reference/candy/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task/) for this candy's install surface. diff --git a/src/content/docs/reference/providers.md b/src/content/docs/reference/providers.md index 4e5b7239..e7045bf1 100644 --- a/src/content/docs/reference/providers.md +++ b/src/content/docs/reference/providers.md @@ -5,7 +5,7 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, -**205 words across 194 plugin candies, 131 compiled into the binary.** Every reserved word charly can dispatch, and the plugin candy that serves it. A word's class tells you where it appears: a `verb` in a plan step, a `kind` as an entity's kind key, a `command` as a `charly ` subcommand, and so on. +**205 words across 196 plugin candies, 132 compiled into the binary.** Every reserved word charly can dispatch, and the plugin candy that serves it. A word's class tells you where it appears: a `verb` in a plan step, a `kind` as an entity's kind key, a `command` as a `charly ` subcommand, and so on. ## `agent-runtime` — 2 words @@ -21,11 +21,11 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | Word | Served by | |---|---| -| `box` | [plugin-build](/reference/plugin/github-com-opencharly-plugin-build-v2026-287-2220/plugin-build/) | +| `box` | [plugin-build](/reference/plugin/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build/) | | `box` | [plugin-build](/reference/plugin/github-com-opencharly-plugin-build-v2026-296-1104/plugin-build/) | -| `ensure` | [plugin-build](/reference/plugin/github-com-opencharly-plugin-build-v2026-287-2220/plugin-build/) | +| `ensure` | [plugin-build](/reference/plugin/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build/) | | `ensure` | [plugin-build](/reference/plugin/github-com-opencharly-plugin-build-v2026-296-1104/plugin-build/) | -| `generate` | [plugin-build](/reference/plugin/github-com-opencharly-plugin-build-v2026-287-2220/plugin-build/) | +| `generate` | [plugin-build](/reference/plugin/github-com-opencharly-plugin-build-v2026-293-0926/plugin-build/) | | `generate` | [plugin-build](/reference/plugin/github-com-opencharly-plugin-build-v2026-296-1104/plugin-build/) | ## `builder` — 6 words @@ -60,7 +60,7 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | `bpf` | [plugin-bpf](/reference/plugin/github-com-opencharly-plugin-bpf-v2026-260-1008/plugin-bpf/) | | `bpf` | [plugin-bpf](/reference/plugin/github-com-opencharly-plugin-bpf-v2026-271-2243/plugin-bpf/) | | `build` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | -| `build:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `build:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `cache` | [plugin-cache](/reference/plugin/github-com-opencharly-plugin-cache-v2026-271-2314/plugin-cache/) | | `candy` | [plugin-candy](/reference/plugin/github-com-opencharly-plugin-candy-v2026-242-0526/plugin-candy/) | | `candy` | [plugin-candy](/reference/plugin/github-com-opencharly-plugin-candy-v2026-281-0948/plugin-candy/) | @@ -69,7 +69,7 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | `cat` | [plugin-authoring](/reference/plugin/github-com-opencharly-plugin-authoring-v2026-242-0525/plugin-authoring/) | | `cat:box` | [plugin-authoring](/reference/plugin/github-com-opencharly-plugin-authoring-v2026-271-2244/plugin-authoring/) | | `check` | [plugin-check](/reference/plugin/github-com-opencharly-plugin-check-v2026-242-2127/plugin-check/) | -| `check` | [plugin-check](/reference/plugin/github-com-opencharly-plugin-check-v2026-287-1745/plugin-check/) | +| `check` | [plugin-check](/reference/plugin/github-com-opencharly-plugin-check-v2026-298-0205/plugin-check/) | | `clean` | [plugin-clean](/reference/plugin/github-com-opencharly-plugin-clean-v2026-242-0526/plugin-clean/) | | `clean` | [plugin-clean](/reference/plugin/github-com-opencharly-plugin-clean-v2026-287-2341/plugin-clean/) | | `cmd` | [plugin-cmd](/reference/plugin/github-com-opencharly-plugin-cmd-v2026-242-0526/plugin-cmd/) | @@ -92,42 +92,43 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | `feature` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | | `feature` | [plugin-feature](/reference/plugin/github-com-opencharly-plugin-feature-v2026-242-0530/plugin-feature/) | | `feature` | [plugin-feature](/reference/plugin/github-com-opencharly-plugin-feature-v2026-272-0145/plugin-feature/) | -| `feature:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `feature:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `fetch` | [plugin-authoring](/reference/plugin/github-com-opencharly-plugin-authoring-v2026-242-0525/plugin-authoring/) | | `fetch:box` | [plugin-authoring](/reference/plugin/github-com-opencharly-plugin-authoring-v2026-271-2244/plugin-authoring/) | | `generate` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | -| `generate:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `generate:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `gh` | [plugin-gh](/reference/plugin/github-com-opencharly-plugin-gh-v0-2026281-737/plugin-gh/) | | `herdr` | [plugin-herdr](/reference/plugin/github-com-opencharly-plugin-herdr-v2026-245-1008/plugin-herdr/) | | `herdr` | [plugin-herdr](/reference/plugin/github-com-opencharly-plugin-herdr-v2026-251-0850/plugin-herdr/) | | `inspect` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | -| `inspect:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `inspect:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `labels` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | -| `labels:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `labels:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `list` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | -| `list:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `list:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `load` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | -| `load:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `load:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `logs` | [plugin-pod](/reference/plugin/github-com-opencharly-plugin-pod-v2026-242-0531/plugin-pod/) | | `logs` | [plugin-pod](/reference/plugin/github-com-opencharly-plugin-pod-v2026-274-0652/plugin-pod/) | | `mcp` | [plugin-mcp](/reference/plugin/github-com-opencharly-plugin-mcp-v2026-237-1425/plugin-mcp/) | | `mcp` | [plugin-mcp](/reference/plugin/github-com-opencharly-plugin-mcp-v2026-272-0329/plugin-mcp/) | | `merge` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | -| `merge:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `merge:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `migrate` | [plugin-migrate](/reference/plugin/github-com-opencharly-plugin-migrate-v2026-242-0530/plugin-migrate/) | -| `migrate` | [plugin-migrate](/reference/plugin/github-com-opencharly-plugin-migrate-v2026-280-2238/plugin-migrate/) | +| `migrate` | [plugin-migrate](/reference/plugin/github-com-opencharly-plugin-migrate-v2026-295-1526/plugin-migrate/) | | `new` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | -| `new:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `new:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `ollama` | [plugin-ollama](/reference/plugin/github-com-opencharly-plugin-ollama-v2026-239-1609/plugin-ollama/) | | `ollama` | [plugin-ollama](/reference/plugin/github-com-opencharly-plugin-ollama-v2026-242-0532/plugin-ollama/) | | `ollama` | [plugin-ollama](/reference/plugin/github-com-opencharly-plugin-ollama-v2026-272-0330/plugin-ollama/) | +| `ollama` | [plugin-ollama](/reference/plugin/github-com-opencharly-plugin-ollama-v2026-289-0014/plugin-ollama/) | | `pipeline` | [plugin-pipeline](/reference/plugin/github-com-opencharly-plugin-pipeline-v2026-282-2329/plugin-pipeline/) | | `preempt` | [plugin-preempt](/reference/plugin/github-com-opencharly-plugin-preempt-v2026-242-0533/plugin-preempt/) | | `preempt` | [plugin-preempt](/reference/plugin/github-com-opencharly-plugin-preempt-v2026-274-0646/plugin-preempt/) | | `pull` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | -| `pull:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `pull:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `reconcile` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | -| `reconcile:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `reconcile:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `refresh` | [plugin-authoring](/reference/plugin/github-com-opencharly-plugin-authoring-v2026-242-0525/plugin-authoring/) | | `refresh:box` | [plugin-authoring](/reference/plugin/github-com-opencharly-plugin-authoring-v2026-271-2244/plugin-authoring/) | | `remove` | [plugin-pod](/reference/plugin/github-com-opencharly-plugin-pod-v2026-242-0531/plugin-pod/) | @@ -154,7 +155,7 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | `stop` | [plugin-pod](/reference/plugin/github-com-opencharly-plugin-pod-v2026-242-0531/plugin-pod/) | | `stop` | [plugin-pod](/reference/plugin/github-com-opencharly-plugin-pod-v2026-274-0652/plugin-pod/) | | `task` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-276-1230/plugin-task/) | -| `task` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task/) | +| `task` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task/) | | `tmux` | [plugin-agent](/reference/plugin/github-com-opencharly-plugin-agent-v2026-242-0525/plugin-agent/) | | `tmux` | [plugin-agent](/reference/plugin/github-com-opencharly-plugin-agent-v2026-271-2242/plugin-agent/) | | `tui` | [plugin-agent](/reference/plugin/github-com-opencharly-plugin-agent-v2026-242-0525/plugin-agent/) | @@ -162,7 +163,7 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | `update` | [plugin-pod](/reference/plugin/github-com-opencharly-plugin-pod-v2026-242-0531/plugin-pod/) | | `update` | [plugin-pod](/reference/plugin/github-com-opencharly-plugin-pod-v2026-274-0652/plugin-pod/) | | `validate` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-242-0526/plugin-box/) | -| `validate:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-288-0503/plugin-box/) | +| `validate:box` | [plugin-box](/reference/plugin/github-com-opencharly-plugin-box-v2026-301-1542/plugin-box/) | | `vm` | [plugin-vm](/reference/plugin/github-com-opencharly-plugin-vm-v2026-242-1912/plugin-vm/) | | `vm` | [plugin-vm](/reference/plugin/github-com-opencharly-plugin-vm-v2026-287-2356/plugin-vm/) | | `volume` | [plugin-pod](/reference/plugin/github-com-opencharly-plugin-pod-v2026-242-0531/plugin-pod/) | @@ -226,7 +227,7 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | `skill` | [plugin-harness-kind](/reference/plugin/github-com-opencharly-plugin-harness-kind-v2026-242-0529/plugin-harness-kind/) | | `skill` | [plugin-harness-kind](/reference/plugin/github-com-opencharly-plugin-harness-kind-v2026-288-1214/plugin-harness-kind/) | | `task` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-276-1230/plugin-task/) | -| `task` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task/) | +| `task` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task/) | | `vm` | [plugin-substrate](/reference/plugin/github-com-opencharly-plugin-substrate-v2026-242-0533/plugin-substrate/) | | `vm` | [plugin-substrate](/reference/plugin/github-com-opencharly-plugin-substrate-v2026-274-0652/plugin-substrate/) | @@ -305,6 +306,7 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | `command` | [plugin-command](/reference/plugin/github-com-opencharly-plugin-command-v2026-242-0527/plugin-command/) | | `command` | [plugin-command](/reference/plugin/github-com-opencharly-plugin-command-v2026-277-0738/plugin-command/) | | `crabbox` | [plugin-crabbox](/reference/plugin/github-com-opencharly-plugin-crabbox-v2026-272-0026/plugin-crabbox/) | +| `crabbox` | [plugin-crabbox](/reference/plugin/github-com-opencharly-plugin-crabbox-v2026-293-1011/plugin-crabbox/) | | `cstream` | [plugin-cstream](/reference/plugin/github-com-opencharly-plugin-cstream-v2026-272-0722/plugin-cstream/) | | `cua` | [plugin-cua](/reference/plugin/github-com-opencharly-plugin-cua-v2026-272-0027/plugin-cua/) | | `dbus` | [plugin-dbus](/reference/plugin/github-com-opencharly-plugin-dbus-v2026-237-1417/plugin-dbus/) | @@ -339,12 +341,12 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | `file` | [plugin-file](/reference/plugin/github-com-opencharly-plugin-file-v2026-242-2145/plugin-file/) | | `file` | [plugin-file](/reference/plugin/github-com-opencharly-plugin-file-v2026-272-0142/plugin-file/) | | `file-parity` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-276-1230/plugin-task/) | -| `file-parity` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task/) | +| `file-parity` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task/) | | `gate` | [plugin-pipeline](/reference/plugin/github-com-opencharly-plugin-pipeline-v2026-282-2329/plugin-pipeline/) | | `generate` | [plugin-pipeline](/reference/plugin/github-com-opencharly-plugin-pipeline-v2026-282-2329/plugin-pipeline/) | | `gh` | [plugin-gh](/reference/plugin/github-com-opencharly-plugin-gh-v0-2026281-737/plugin-gh/) | | `git-submodules` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-276-1230/plugin-task/) | -| `git-submodules` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task/) | +| `git-submodules` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task/) | | `gpu` | [plugin-gpu](/reference/plugin/github-com-opencharly-plugin-gpu-v2026-242-0529/plugin-gpu/) | | `gpu` | [plugin-gpu](/reference/plugin/github-com-opencharly-plugin-gpu-v2026-272-0959/plugin-gpu/) | | `herdr` | [plugin-herdr](/reference/plugin/github-com-opencharly-plugin-herdr-v2026-245-1008/plugin-herdr/) | @@ -369,7 +371,7 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | `media` | [plugin-pipeline](/reference/plugin/github-com-opencharly-plugin-pipeline-v2026-282-2329/plugin-pipeline/) | | `mise` | [plugin-mise](/reference/plugin/github-com-opencharly-plugin-mise-v2026-274-2100/plugin-mise/) | | `module-pins` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-276-1230/plugin-task/) | -| `module-pins` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task/) | +| `module-pins` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task/) | | `mount` | [plugin-mount](/reference/plugin/github-com-opencharly-plugin-mount-v2026-242-0530/plugin-mount/) | | `mount` | [plugin-mount](/reference/plugin/github-com-opencharly-plugin-mount-v2026-272-0338/plugin-mount/) | | `oci` | [plugin-oci](/reference/plugin/github-com-opencharly-plugin-oci-v2026-242-0531/plugin-oci/) | @@ -385,7 +387,7 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | `process` | [plugin-process](/reference/plugin/github-com-opencharly-plugin-process-v2026-242-0533/plugin-process/) | | `process` | [plugin-process](/reference/plugin/github-com-opencharly-plugin-process-v2026-272-0440/plugin-process/) | | `prune` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-276-1230/plugin-task/) | -| `prune` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task/) | +| `prune` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task/) | | `punktfunk` | [plugin-punktfunk](/reference/plugin/github-com-opencharly-plugin-punktfunk-v2026-272-0440/plugin-punktfunk/) | | `quickshell` | [plugin-quickshell](/reference/plugin/github-com-opencharly-plugin-quickshell-v2026-243-1500/plugin-quickshell/) | | `quickshell` | [plugin-quickshell](/reference/plugin/github-com-opencharly-plugin-quickshell-v2026-272-0445/plugin-quickshell/) | @@ -397,9 +399,9 @@ description: "Every reserved word — verb, kind, deploy target, step, builder, | `service` | [plugin-service](/reference/plugin/github-com-opencharly-plugin-service-v2026-272-0417/plugin-service/) | | `spice` | [plugin-spice](/reference/plugin/github-com-opencharly-plugin-spice-v2026-272-0430/plugin-spice/) | | `splice-region` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-276-1230/plugin-task/) | -| `splice-region` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task/) | +| `splice-region` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task/) | | `task` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-276-1230/plugin-task/) | -| `task` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-283-0105/plugin-task/) | +| `task` | [plugin-task](/reference/plugin/github-com-opencharly-plugin-task-v2026-300-0951/plugin-task/) | | `transcode` | [plugin-media](/reference/plugin/github-com-opencharly-plugin-media-v2026-272-1009/plugin-media/) | | `tunnel` | [plugin-tunnel](/reference/plugin/github-com-opencharly-plugin-tunnel-v2026-242-0609/plugin-tunnel/) | | `tunnel` | [plugin-tunnel](/reference/plugin/github-com-opencharly-plugin-tunnel-v2026-272-0423/plugin-tunnel/) |