| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 1 | 8 | 49 | 2% |
| Commands | 1 | 1 | 12 | 7% |
| Section tags | 3 | 2 | 8 | 23% |
What each file covers
Sections
1 shared · 8 only in A · 49 only in B- − AGENTS.md
- − What this project is
- − Working on this repo — the rules
- − Build / test / lint
- − Versioning
- − Recommended companion skill — `garrytan/gstack`
- − Per-platform integration (when working on platform-specific bits)
- − Reference
- + CLAUDE.md
- + What is open-forge
- + Architecture — 3 layers, asked in 3 questions
- + File layout for the 3 layers
- + A fourth orchestration layer — bundles
- + Is this software in scope?
- + Inclusion criteria — recipe is in scope when ALL are true
- + Exclusion criteria — out of scope
- + Edge cases — borderline classes
- + When in doubt
- + Operating principles
- + Credential handling (expanded from Operating Principle #3)
- + The five patterns (priority order)
- + Hard rules
- + Strict doc-verification policy (mandatory before writing any recipe)
- + Before writing or expanding any project / infra recipe
- + What counts as "official"
- + When upstream-doc fetch fails
- + Community-maintained methods — flagging requirements
- + Retroactive application
- + Two-tier coverage model
- + Tier 1 — verified recipes (the catalogue)
- + Tier 2 — derived live from upstream docs
- + Routing
- + Quality boundary
- + Tier 2 → Tier 1 graduation criteria
- + Issue-driven contribution model
- + Three input channels
- + Why issues, not PRs
- + Direct human PRs
- + Sanitization principles
- + Always strip
- + Multi-step consent (no auto-post, ever)
- + When reviewing PRs sourced from issues
- + Processing incoming issues
- + 1. Triage
- + 2. Validate against upstream
- + 3. Author the patch
- + 4. Open the PR
- + 5. State-machine via labels
- + 6. Conflicts and ambiguity
- + Companion skills & MCPs
- + Recommended companion: `garrytan/gstack`
- + Recipe structure (must-have sections)
- + First-run discipline
- + File layout
- + Versioning + publish flow
- + Refactor (started 2026-04-24, completed 2026-04-26)
- + Behavioral guidelines (echoes of bota CLAUDE.md, kept here for autonomy)
- Author convention
Commands
1 shared · 1 only in A · 12 only in B- − git config
- + pip install
- + docker-compose.yml
- + git clone https://github.com/<org>/<repo>.wiki.git
- + git clone
- + helm
- + helm-generator
- + terraform-generator
- + docker
- + kubectl
- + terraform
- + kubectl get pods -o json
- + gh-fix-ci
- git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack \
Section tags
3 shared · 2 only in A · 8 only in B- − test
- − lint-format
- + setup
- + code-style
- + architecture
- + testing-strategy
- + git-pr
- + deployment
- + agent-behaviour
- + docs
- build
- security
- do-not
Line diff
zhangqi444/open-forge · AGENTS.md
@@ −1 @@
1# AGENTS.md
2
3[`agents.md`](https://agents.md) compatibility — this file orients any AI coding agent (Claude Code, Codex, Cursor, Aider, Continue.dev, OpenClaw, Hermes-Agent, or a custom tools-using LLM) that's working *on* the open-forge codebase. End users **using** the open-forge skill to deploy software should look at [SKILL.md](plugins/open-forge/skills/open-forge/SKILL.md) instead.
4
5> **Canonical reference.** This file is intentionally short. The full architectural treatment, strict-doc-verification policy, two-tier coverage model, sanitization rules, and issue-processing workflow live in [**CLAUDE.md**](CLAUDE.md). Read that for the complete picture — AGENTS.md is the agents.md-standard landing page that points at it.
6
7## What this project is
8
9`open-forge` is a guided self-hosting **skill** distributed via Claude Code's plugin marketplace and adapted for 6+ other AI platforms. It walks users from *"I have a cloud account and a domain"* to *"working app at https://my.domain"* via a phased workflow (preflight → provision → dns → tls → smtp → inbound → hardening → feedback) using 2,200+ verified recipes plus curated bundles for goal-shaped requests (AI homelab, privacy stack) plus a live-derived fallback for the long tail.
10
11This **isn't a typical software repo** — it's a library of platform-agnostic markdown recipes + a thin Bash build script. There's no compiled artifact, no test suite, no lint config. The "build" is regenerating distribution bundles from canonical sources.
12
13## Working on this repo — the rules
14
15Per [CLAUDE.md](CLAUDE.md):
16
171. **No human PRs — issues only.** Catalog evolves through GitHub issues processed by AI sessions. See [`.github/ISSUE_TEMPLATE/`](.github/ISSUE_TEMPLATE/) for the three input channels (recipe-feedback, software-nomination, method-proposal). Direct PRs are discouraged; if you submit one, the strict-doc policy still applies.
182. **Strict-doc-verification policy.** Every install method in every recipe must cite an upstream URL (`> **Source:** <url>`). Community-maintained methods open with the required ⚠️ blockquote. The README is necessary but **not sufficient** — also read the upstream docs site, repo `docs/install/` tree, and wiki. If upstream-doc fetch fails, **stop**; do not write speculative content. Full rules in [CLAUDE.md § Strict doc-verification policy](CLAUDE.md#strict-doc-verification-policy-mandatory-before-writing-any-recipe).
193. **Sanitization principles.** User-shared content (deploy logs, gotchas, error output) must be stripped of identifiers (domains, IPs, SSH keys, API keys, AWS account IDs, emails) before being merged into recipes or posted to GitHub issues. Full strip-list with regex patterns in [CLAUDE.md § Sanitization principles](CLAUDE.md#sanitization-principles).
204. **Two-tier coverage model.** Tier 1 = verified recipes in `references/projects/`. Tier 2 = live-derived from upstream docs at runtime for software not yet in the catalog. Promotion criteria in [CLAUDE.md § Two-tier coverage model](CLAUDE.md#two-tier-coverage-model).
215. **In-scope test.** Before adding a recipe: deployable service / static-site generator / CLI agent / AI inference server / CI runner / storage backend → ✅. Library / desktop app / SaaS-only → ❌. Decision rule + edge-case table in [CLAUDE.md § Is this software in scope?](CLAUDE.md#is-this-software-in-scope).
22
23## Build / test / lint
24
25There is no traditional build / test / lint pipeline. The single build artifact is the multi-platform distribution bundles under `dist/`:
26
27```bash
28./scripts/build-dist.sh all # regenerate bundles for all 7 platforms
29./scripts/build-dist.sh codex # just Codex
30./scripts/build-dist.sh openclaw # just OpenClaw
31```
32
33**Required after touching any of:** `CLAUDE.md`, `plugins/open-forge/skills/open-forge/SKILL.md`, `plugins/open-forge/skills/open-forge/references/modules/*.md`. The bundles concatenate these files; they drift if not regenerated, which silently breaks non-Claude-Code platforms.
34
35CI enforces this — see [`.github/workflows/dist-bundles.yml`](.github/workflows/dist-bundles.yml). If the `dist-bundles-up-to-date` check fails on your PR, the fix is always: run `./scripts/build-dist.sh all` from the repo root, commit the changes, push.
36
37## Versioning
38
39`plugins/open-forge/.claude-plugin/plugin.json` `version` controls what the Claude Code marketplace fetches.
40
41- **Bump on**: skill description change, new project / runtime / infra / module, major recipe rewrite, anything user-visible.
42- **Don't bump on**: typo fixes, internal cleanups, lint-only changes.
43
44## Author convention
45
46Commits authored as `Qi Zhang <zhangqi444@gmail.com>` — set inline via env vars (`GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`, `GIT_COMMITTER_EMAIL`). Never write to `git config`.
47
48## Recommended companion skill — `garrytan/gstack`
49
50If you're a Claude Code session working on this repo, install [`garrytan/gstack`](https://github.com/garrytan/gstack) — Garry Tan's SDLC slash-command bundle. Its `/review`, `/qa`, `/ship`, `/cso`, `/learn`, and `/plan-eng-review` commands map directly onto the maintenance workflows used here. Install:
51
52```bash
53git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack \
54 && cd ~/.claude/skills/gstack && ./setup
55```
56
57See [CLAUDE.md § Recommended companion: garrytan/gstack](CLAUDE.md#recommended-companion-garrytangstack) for the per-command mapping. Optional but encouraged.
58
59## Per-platform integration (when working on platform-specific bits)
60
61If your patch touches platform-specific behavior, check the per-platform integration docs:
62
63- [Claude Code](README.md#install) — canonical platform; auto-discovers via plugin marketplace
64- [Codex](docs/platforms/codex.md) — system-prompt embedding or workspace files
65- [Cursor](docs/platforms/cursor.md) — `.cursor/rules/` bundle
66- [Aider](docs/platforms/aider.md) — `--read` flags + `CONVENTIONS.md`
67- [Continue.dev](docs/platforms/continue.md) — context provider + slash command
68- [OpenClaw](docs/platforms/openclaw.md) — workspace skill
69- [Hermes-Agent](docs/platforms/hermes.md) — user skill
70- [Generic agents](docs/platforms/generic.md) — any tools-using LLM
71
72Cross-platform behavior changes (e.g. credential handling) live in `references/modules/` so all platforms inherit them through the dist bundles.
73
74## Reference
75
76For everything not covered above:
77- **[BRD.md](BRD.md)** — *intent*: why the project exists, who it's for, success criteria, what we're explicitly not building.
78- **[CLAUDE.md](CLAUDE.md)** — *policy*: what's in scope, strict-doc rules, sanitization, processing workflow.
79- **[ARCHITECTURE.md](ARCHITECTURE.md)** — *system shape*: actors, data flow, state stores, quality gates, cadence.
80
81User-facing project documentation lives in [README.md](README.md). End-user-skill content lives in [plugins/open-forge/skills/open-forge/SKILL.md](plugins/open-forge/skills/open-forge/SKILL.md).
82
zhangqi444/open-forge · CLAUDE.md
@@ +1 @@
1# CLAUDE.md
2
3Instructions for any AI coding session working *on* the open-forge plugin (not running it). Different audience from `plugins/open-forge/skills/open-forge/SKILL.md`, which is what an end-user's agent reads to *use* the plugin.
4
5> **Also accessible as [`AGENTS.md`](AGENTS.md)** per the [agents.md](https://agents.md) convention. AGENTS.md is a thin landing page that points here; this file is the canonical reference. Tools that look for either filename find their way in.
6>
7> **For *system shape* (actors, data flow, state stores, quality gates, cadence) see [`ARCHITECTURE.md`](ARCHITECTURE.md).** This file is the *policy* (what's in scope, strict-doc rules, sanitization principles, processing workflow); ARCHITECTURE.md is how the policy is operationalized as a maintenance system.
8>
9> **For *intent* — why the project exists, who it's for, what success looks like, what we're explicitly not building — see [`BRD.md`](BRD.md).** When a strategic decision feels off (or when a recipe-authoring choice has policy ambiguity), check BRD.md before re-litigating.
10
11## What is open-forge
12
13A Claude Code plugin/skill that turns "read a README, copy-paste 30 lines of bash, debug for hours" into a guided chat where Claude executes everything via the user's local CLI tools and the user only makes choices.
14
15## Architecture — 3 layers, asked in 3 questions
16
17A deployment is a tuple of three independent axes, asked in this order:
18
19| # | Question | Layer | Examples |
20|---|---|---|---|
21| 1 | **What** to host? | software | OpenClaw, Ghost, Mastodon, Vaultwarden, Nextcloud |
22| 2 | **Where** to host? | infra (cloud or local) | AWS / Hetzner / DigitalOcean / GCP / Azure / bring-your-own-VPS / **localhost** |
23| 3 | **How** to host (within that cloud)? | infra-service + runtime | AWS: Lightsail blueprint, Lightsail Ubuntu + Docker, EC2 + native, EKS, ECS Fargate. Hetzner: Cloud CX + Docker, Cloud CX + native. localhost: Docker Desktop, native. |
24
25The third question is *dynamically generated* from (software, cloud) — different clouds expose different compute services, and some software has vendor-bundled blueprints on specific clouds.
26
27**Some infra services bundle the runtime** — EKS → Kubernetes, Lightsail OpenClaw blueprint → vendor's pre-baked install. In those cases the "runtime" question is not asked separately. **Other services give runtime choice** — EC2, plain VPS, localhost — there we ask Docker vs native vs k3s.
28
29**Reusability is the test.** "Install Docker + run docker-compose" is the same on Lightsail Ubuntu, Hetzner CX-line, a DO droplet, and a localhost — write it once in the runtime layer, reference from every project. "Install k3s" is the same across clouds — write it once. Project recipes should be 80% software-specific concerns and contain *no* per-runtime install commands beyond a one-line link.
30
31### File layout for the 3 layers
32
33```
34references/
35├── projects/<sw>.md # software layer (thin)
36├── infra/
37│ ├── aws/
38│ │ ├── lightsail-blueprint.md # vendor-bundled, software-specific
39│ │ ├── lightsail-ubuntu.md # Lightsail as a plain VM
40│ │ ├── ec2.md
41│ │ ├── eks.md
42│ │ └── ecs-fargate.md
43│ ├── hetzner/cloud-cx.md
44│ ├── digitalocean/droplet.md
45│ ├── gcp/compute-engine.md
46│ ├── byo-vps.md # user provides any Linux VPS, Claude SSH-es in
47│ └── localhost.md # user's own machine, Claude runs commands directly
48├── runtimes/
49│ ├── docker.md # reusable wherever Docker works
50│ ├── native.md # native installer (curl/apt)
51│ └── kubernetes.md # reusable across EKS/GKE/AKS/k3s
52└── modules/ # cross-cutting (preflight, dns, tls, smtp providers, inbound forwarders, tunnels, backups, monitoring)
53```
54
55`localhost.md` is a first-class infra — for many projects (especially OpenClaw), running locally is the default upstream path. Same conversational UX as a cloud deploy; differences are: no SSH (Claude runs commands directly), no provisioning, public reach via tunnel (`references/modules/tunnels.md`).
56
57### A fourth orchestration layer — bundles
58
59Above software / infra / runtime sits an optional **bundle** layer (`references/bundles/`). A bundle is a *recipe-of-recipes* — it pairs commonly-co-deployed software for goal-shaped user requests (*"set up an AI homelab"*) and ships the cross-software wiring (env vars / DNS / ports between constituents). Bundles don't replace single-recipe routing; they're an additional entry point for goal-shaped intents.
60
61Per *Tier 2 → Tier 1 graduation criteria* below, bundles aren't speculative authoring — they orchestrate **existing Tier 1 recipes** only. If a constituent recipe gets demoted, the bundle goes with it. New bundles get added when 3+ users (or one repeat user) ask for the same combination. Current bundles: `bundles/ai-homelab.md` (Ollama + Open WebUI + AnythingLLM + Aider) and `bundles/privacy-stack.md` (Pi-hole + Vaultwarden + Headscale OR wg-easy).
62
63## Is this software in scope?
64
65open-forge is for **deployable self-hosted services**. Use these criteria when deciding whether a piece of software belongs as a Tier 1 recipe (see *Two-tier coverage model* below).
66
67### Inclusion criteria — recipe is in scope when ALL are true
68
691. **Software runs as a deployed service or is served from a host the user owns**: long-running daemon, scheduled job, web service, API, CLI agent, or static asset published to a host.
702. **Source code or binaries are user-installable on infrastructure they control**: cloud VM, VPS, k3s cluster, or localhost. Paid AMIs / vendor stacks (Bitnami, Dify Premium, etc.) count — closed-source SaaS-only does not.
713. **At least one upstream-documented install method or canonical install artifact in-repo** exists, so the strict-doc-policy below has something to verify against.
72
73### Exclusion criteria — out of scope
74
75- **Pure libraries / SDKs / packages** that you `import` or call (Unsloth, requests, lodash). No deployment surface.
76- **Desktop / mobile end-user apps** with no self-hosted server side (Slack desktop, VS Code, Discord client).
77- **SaaS / managed-only products** with no self-host distribution (Notion, Linear, Figma).
78- **Dev-only tooling that runs ephemerally on a developer machine** and is never deployed (Storybook *dev* mode, Vite dev server, REPLs).
79
80### Edge cases — borderline classes
81
82| Class | Verdict | Recipe shape |
83|---|---|---|
84| **Static-site generators** (Hugo, Jekyll, Docusaurus, Storybook in production-preview mode) | ✅ in scope | Thin: `<sg> build` → static dir → deploy via a static-host module (nginx / S3+CDN / Pages). The SG-specific bit is build config, theme path, content tree. |
85| **CLI agents** (Aider, OpenClaw, Hermes-Agent) | ✅ in scope | Install on a host, run as daemon or interactive CLI. Standard recipe shape. |
86| **AI inference servers** (vLLM, Ollama, TGI) | ✅ in scope | Deployed services exposing HTTP APIs. Standard recipe shape. |
87| **AI training libraries** (Unsloth, axolotl, transformers) | ❌ out of scope | Libraries called from training scripts, not deployed services. If a "training environments" track ever exists, it's a separate category — not project recipes under `references/projects/`. |
88| **CI runners** (GitHub Actions self-hosted, Buildkite agent) | ✅ in scope | Long-running daemon attached to a control plane. Standard recipe shape. |
89| **Standalone databases** (Postgres, ClickHouse, Redis) | ⚠️ borderline | Useful but usually a dependency of another recipe rather than a deployment goal. Document as a supporting service inside the consuming recipe; only write a standalone recipe when there's clear demand. |
90| **Storage backends** (MinIO, SeaweedFS, Garage) | ✅ in scope | Self-hostable services with HTTP APIs. Standard recipe shape. |
91
92### When in doubt
93
94Ask: *"Would the user need open-forge to walk them through provisioning + DNS + TLS + ongoing lifecycle for this?"* If yes, write a recipe. If no (e.g. they'd just `pip install` it inside their own scripts), it's out of scope — or fall back to Tier 2 (below) for one-off requests.
95
96## Operating principles
97
981. **Do more, ask less. Non-tech-friendly.** Default to autonomous execution. Only prompt the user for things only they can decide or provide: credentials, opinionated choices, things that touch their accounts at other companies. Hide everything Claude can figure out from the recipe.
992. **Towards production-ready architecture.** Even single-node hobby deploys should be on a path to backups, monitoring, TLS, key rotation, OS updates, and least-privilege firewalls. Don't write recipes that "work" but leave the system one outage away from data loss.
1003. **Security in mind.** Treat tokens/keys as toxic — never log them, rotate after chat exposure, prefer fragment URLs over query strings. Default firewalls to closed; open ports explicitly. Default to SSH key auth; never password. Let's Encrypt for any public endpoint. Sandbox agent tool execution where the runtime supports it.
1014. **One question at a time.** Use `AskUserQuestion` for structured choices. Reserve free-text for credentials and identifiers (domain names, emails). No upfront questionnaires.
1025. **Auto-install with confirmation, never silently.** If `jq` or `aws` is missing, propose the install command, get one-line approval, then run.
1036. **Reference upstream docs; don't replace them.** Recipes condense and translate upstream documentation into Claude-actionable steps — they aren't the source of truth for the product itself. Always link the upstream pages we summarized (e.g. `docs.openclaw.ai/install/docker`, AWS Lightsail user guide, Bitnami docs). Reasons: (a) users can verify what we condensed, (b) when upstream drifts our recipe goes stale fast and the link is the recovery path, (c) credit where due. **See *Strict doc-verification policy* below — every install method documented by upstream must have its own recipe section, verified against upstream before being written.**
1047. **Don't invent — interface.** open-forge is a chat-friendly interface to existing tools. Claude is the orchestrator; the user's existing software stack (AWS CLI, Docker, openclaw, ssh, gh, registrar UIs) is the substrate. **Do not** build custom DSLs, YAML schemas, CLI tools, deployment managers, or wrappers around upstream tools. **Do not** reimplement what an upstream tool already does (e.g. don't rebuild `openclaw onboard`'s prompts in chat — call the command). The state file is a thin orchestration helper for resume, nothing more. *Caveat:* "don't invent" applies to **fabricating a deployment path the upstream doesn't support** (e.g. authoring a Helm chart for a project that has no chart). It does **not** mean "no tooling." If upstream supports Docker / k8s / Helm / Terraform, lean on every skill and MCP that helps you orchestrate those paths well — see *Companion skills & MCPs* below.
105
106## Credential handling (expanded from Operating Principle #3)
107
108Pasting raw credentials into Claude Code is risky — secrets enter session history, may be relayed via MCP servers, and could appear in shared transcripts. The skill must offer safer alternatives **first** and only fall back to direct paste with explicit risk acknowledgement.
109
110### The five patterns (priority order)
111
112| # | Pattern | When to suggest |
113|---|---|---|
114| 1 | **Local file path** — user gives skill a path; skill `cat`s it | Personal-use API keys; user already has a `.env` or `.secrets` file |
115| 2 | **Env var name** — user pre-exports the secret; skill reads `$<NAME>` | Shell users with secrets in `.envrc` / `.bashrc` |
116| 3 | **Cloud-CLI session** — user runs `<provider> login` ahead of time; skill uses the resulting profile / session | Default for AWS, GCP, Azure, GitHub, DigitalOcean, Hetzner, Cloudflare |
117| 4 | **Secrets-manager reference** — user gives skill a `op://` / `bw://` / `vault://` reference; skill calls the matching CLI just-in-time | Users with proper secret management (1Password, Bitwarden, Vault, AWS Secrets Manager, GCP Secret Manager, `pass`) |
118| 5 | **Direct chat paste** — last resort, requires risk acknowledgement | When patterns 1-4 don't apply; user explicitly opts in |
119
120### Hard rules
121
122- **Always offer the five patterns** when asking for any sensitive input. Don't silently accept a paste; don't assume Claude Code is a vault.
123- **Surface the risk** before accepting a direct paste: *"the key will live in this session's history; rotate after deploy completes."*
124- **Never accept SSH key contents.** Always ask for the key file *path* (skill uses `ssh -i <path>`); never the key material itself in chat.
125- **Validate before proceeding**: `test -r <path>` for file paths; `test -n "$<VAR>"` for env vars; smoke-command for cloud-CLI sessions and secrets-manager refs.
126- **Refuse files with permissions wider than 600**; offer to `chmod 600` first.
127- **Detect accidental pastes** (regex for `re_*`, `sk-*`, `AKIA*`, etc. in a prompt that expected a path) and stop the user before the secret commits to chat.
128- **End-of-deploy rotation reminder** if the user pasted any secret directly during the deploy: list each pasted credential + the provider's dashboard URL; recommend rotating now that the deploy is done.
129
130The full pattern catalog with skill prompt templates, per-credential-class recommendations, and failure-mode handling lives in [`plugins/open-forge/skills/open-forge/references/modules/credentials.md`](plugins/open-forge/skills/open-forge/references/modules/credentials.md).
131
132## Strict doc-verification policy (mandatory before writing any recipe)
133
134Recipes are condensations of upstream docs; condensing what we haven't read is speculation. Past failures (the v0.7.0 Helm chart claim sourced from a search snippet, the v0.6.0 OpenClaw "every blessed path" claim that was 4 of 17 because we trusted the README's enumeration) traced back to this. The policy:
135
136### Before writing or expanding any project / infra recipe
137
1381. **Read the upstream README verbatim.** Not summarized — the actual README. Note: the README is necessary but **not sufficient** — many projects' READMEs are deliberately minimal and point at a separate docs site for install methods.
1392. **Locate the upstream install-method index.** Typically:
140 - The project's docs site (`docs.PROJECT.ai`, `PROJECT.com/docs`, `PROJECT.github.io`, etc.).
141 - The repo's `docs/install/` or `website/docs/getting-started/` tree.
142 - The repo's wiki (often a separate `<repo>.wiki.git` clone).
1433. **Enumerate every method documented under that index.** Include:
144 - First-party install scripts (`install.sh`, `install.ps1`, vendor blueprints).
145 - First-party Docker / Compose / Kubernetes / Helm support.
146 - First-party package-manager support (Homebrew, Nix, Pacman, etc.).
147 - First-party PaaS templates (`fly.toml`, `render.yaml`, Railway / Zeabur / Sealos one-click buttons published by upstream).
148 - First-party cloud templates (Terraform / CDK / Computing Nest published by upstream).
1494. **Read the canonical install artifacts in the repo:** `docker-compose.yml`, `Dockerfile`, `flake.nix`, the project's primary config-file example. These often surface details the docs gloss over (service inventory, env-var matrix).
1505. **Write one section per documented method.** No merging, no skipping. Each section's first line cites the upstream URL it's derived from.
151
152### What counts as "official"
153
154| Source | Official? |
155|---|---|
156| Upstream's own README | ✅ |
157| Upstream's own docs site (linked from README) | ✅ |
158| Upstream's repo `docs/` or `website/` tree | ✅ |
159| Upstream's repo wiki | ✅ |
160| Upstream-published PaaS deploy buttons (Railway/Render/Fly/etc.) where the manifest lives in the upstream repo | ✅ |
161| Community-maintained Docker images / Helm charts when upstream ships none | ⚠️ Allowed but **must be flagged** as "community-maintained, verify source"; recipe lists multiple options (most-active first), doesn't pick a winner |
162| Anything else (third-party blogs, search snippets, my training data) | ❌ Not allowed as the basis for a section. If upstream ships no path for X, do not invent one. |
163
164### When upstream-doc fetch fails
165
166- WebFetch rate-limited / 403 / 404 → try `raw.githubusercontent.com/<org>/<repo>/<branch>/<path>` for repo content.
167- Wiki page WebFetch fails → `git clone https://github.com/<org>/<repo>.wiki.git` and read locally.
168- All fetch paths fail → **stop**. Do not write speculative content. Either: (a) ask the user to paste relevant doc text, (b) wait until access is restored, or (c) write only the sections for methods we *did* read and note in the recipe's TODO that the rest is pending verification.
169
170### Community-maintained methods — flagging requirements
171
172When a recipe documents a method upstream doesn't ship (e.g. A1111 + ComfyUI Docker, Helm charts for many projects), the section MUST:
173
1741. Open with an explicit "community-maintained" note in a blockquote.
1752. List **multiple** options when they exist (most-active first; reference upstream README's pointer if upstream lists them).
1763. Frame commands as "illustrative — verify the README at the version you pull"; never present community-chart `--set` values as authoritative.
1774. Document the gap in the recipe's TODO section: "Verify which community option is most actively maintained at first-deploy time."
178
179### Retroactive application
180
181When this policy is added (or strengthened), every existing recipe must be re-verified against its upstream docs index. If the verification surfaces a missing method, file it in that recipe's TODO, write the missing section, and bump the plugin version.
182
183### When in doubt
184
185Ask the user whether to pause for verification or accept the README's enumeration. Don't silently downgrade thoroughness.
186
187---
188
189## Two-tier coverage model
190
191open-forge ships a finite catalogue of verified recipes (Tier 1) plus a documented fallback for everything else (Tier 2). Both tiers obey the strict-doc-policy above; the difference is *when* the verification happens.
192
193### Tier 1 — verified recipes (the catalogue)
194
195The current set under `references/projects/`. Authored ahead of time, audited against upstream docs, kept current via the first-run discipline + version bumps. **Quality bar:**
196
197- Every install method has a `> **Source:** <upstream URL>` line at the top of its section.
198- Community-maintained methods open with the required ⚠️ blockquote per *Community-maintained methods — flagging requirements*.
199- Gotchas captured from real deploys; TODOs track unresolved verifications.
200- Plugin version bumped on each user-visible change.
201
202### Tier 2 — derived live from upstream docs
203
204When a user asks for software that has no Tier 1 recipe, the skill **falls back** instead of refusing:
205
2061. **Announce the fallback in one sentence**: *"This software isn't in our verified recipe set — I'll fetch upstream docs live and reuse the runtime / infra modules. Treat my output as best-effort, not authoritative."*
2072. **Apply the strict-doc-policy on the fly** — same rules as Tier 1:
208 - Read upstream README via `WebFetch`. If 403/404, fall back to `raw.githubusercontent.com` paths and/or `git clone` the docs repo locally.
209 - Locate the upstream install-method index (docs site, repo `docs/install/` tree, wiki).
210 - Enumerate methods from upstream — **do not invent**. If fetches fail, stop and tell the user; never speculate to fill a gap.
211 - Read canonical install artifacts (`Dockerfile`, `docker-compose.yml`, `helm/`, `flake.nix`).
2123. **Reuse runtime + infra + cross-cutting modules** under `references/runtimes/`, `references/infra/`, `references/modules/` for all the reusable parts (Docker install, k8s prereqs, VM provisioning, DNS, TLS, SMTP). Tier 2 is mostly *software-specific* on top of those — same shape as Tier 1, just authored at request time.
2134. **Cite every upstream URL** the same way Tier 1 does.
2145. **Offer to capture the result** as a new Tier 1 recipe when the deploy succeeds — that's how the catalogue grows. The captured recipe must still go through first-run discipline before claiming Tier 1 status.
215
216### Routing
217
218The skill checks Tier 1 first by name match against `references/projects/*.md`. If no match, fall back to Tier 2 with the announcement above. **Never silently mix tiers** — the user should always know which tier they're in, since the verification depth differs.
219
220### Quality boundary
221
222Tier 2 output is **best-effort, not authoritative.** It will hallucinate at the edges of upstream docs we couldn't fetch; it skips the iterative refinement that Tier 1 recipes get from real deploys. Tell the user this. They're trading verification depth for coverage breadth.
223
224### Tier 2 → Tier 1 graduation criteria
225
226The catalogue grows demand-driven, not by guess. Promote a Tier 2 deploy to a Tier 1 recipe when ANY of:
227
2281. **3+ feedback issues** for the same software (demand signal — see *Issue-driven contribution model*).
2292. **Same user has deployed it 3+ times** and asks for first-run discipline applied.
2303. **A Tier 2 deploy surfaced a non-obvious gotcha** that's likely to bite the next person — capture the gotcha as a recipe even if demand is small (one-shot promotion is allowed when the value is in the captured knowledge).
2314. **A maintainer chooses to deploy the software themselves** (sunk cost is acceptable).
232
233Don't author Tier 1 recipes speculatively from a "popular self-host" list — without a real demand signal, the compounding effect can't kick in and the upfront cost goes to waste.
234
235---
236
237## Issue-driven contribution model
238
239The catalogue evolves through GitHub issues, not direct human PRs. AI coding sessions (whether triggered by a maintainer running this skill, by a scheduled job, or by a webhook) read incoming issues, verify them against upstream docs per *Strict doc-verification policy*, and author patches.
240
241### Three input channels
242
243GitHub issue templates under `.github/ISSUE_TEMPLATE/` define the structured input:
244
245| Template | When to use | Filed by |
246|---|---|---|
247| `recipe-feedback.yml` | A user deployed via the skill and wants to suggest recipe edits (gotchas captured, install steps that surprised them, sections that were wrong/outdated). The skill drafts these automatically at the end of a deploy. | End user (skill-assisted) |
248| `software-nomination.yml` | A user wants software added to the Tier 1 catalogue. Must include rationale + upstream URL + the user's intended deploy combo. | End user |
249| `method-proposal.yml` | A user knows an upstream-supported install method that an existing recipe doesn't cover. Must include the upstream URL where the method is documented. | End user |
250
251A blank-issue / off-template issue is treated as a request for routing — close politely with a pointer to the templates.
252
253### Why issues, not PRs
254
255- **Sanitization happens at submission time.** The skill (or a careful manual filer) redacts identifiers before posting; the issue templates encode the structure. PRs from random users could include credentials in commit history that can't be cleanly removed.
256- **Verification happens centrally.** Every change is re-verified against upstream by the AI session that processes the issue, not trusted because someone filed a PR.
257- **Demand signal lives in the issue stream.** Issues with the most thumbs-up / cross-linking / repeat filings are the demand signal that drives Tier 2 → Tier 1 graduation.
258
259### Direct human PRs
260
261Discouraged. If a maintainer writes a PR by hand, it's still subject to the strict-doc-policy and recipe-structure rules — the issue model is the documented contribution path.
262
263---
264
265## Sanitization principles
266
267User-shared content (deployment logs, gotchas, error output) routinely contains identifiers that **must not** end up in the public repo. Both the skill (when drafting issue content) and any session reviewing user-supplied content (when accepting a PR sourced from an issue) must apply these rules.
268
269### Always strip
270
271| Class | Replace with |
272|---|---|
273| Domain names (apex / canonical / admin) | `${CANONICAL_HOST}` / `${APEX}` / `${ADMIN_DOMAIN}` |
274| IP addresses (public + private + IPv6) | `${PUBLIC_IP}` / `${PRIVATE_IP}` |
275| SSH key paths and contents | `${KEY_PATH}` / `<REDACTED-SSH-KEY>` |
276| API keys and bearer tokens (regex: `re_[A-Za-z0-9_]+`, `SG\.[A-Za-z0-9._-]+`, `sk-[A-Za-z0-9]+`, `xox[bp]-[A-Za-z0-9-]+`, `ghp_[A-Za-z0-9]+`, AWS access keys `AKIA[0-9A-Z]{16}` + secret `[A-Za-z0-9/+=]{40}`, GCP service-account JSON, generic `Bearer [A-Za-z0-9._-]{20,}`) | `<REDACTED>` |
277| AWS account IDs (12 consecutive digits in AWS context) | `${AWS_ACCOUNT}` |
278| AWS profile names | `${AWS_PROFILE}` |
279| Email addresses (LE email, SMTP from-address, user identity) | `${EMAIL}` |
280| State-file contents from `~/.open-forge/deployments/<name>.yaml` | Reference the file by name only, never paste contents |
281| Hostnames embedded in URLs that include the user's domain | `https://${CANONICAL_HOST}/path` |
282| Anything from the user's clipboard / env vars they pasted into chat | `<REDACTED>` |
283
284### Multi-step consent (no auto-post, ever)
285
286The skill flow when posting feedback to GitHub:
287
2881. **Opt-in prompt** — *"Want to share what you learned?"* User must explicitly opt in.
2892. **Show the redacted draft in chat** — full text, before any submission attempt.
2903. **Confirm post?** — explicit "yes" required.
2914. **If user edits the draft**, re-show + re-confirm before submitting.
2925. **Standing reminder text** in the prompt: *"GitHub issues are public and permanent. Once posted, this can't be unposted. Review every line; edit if anything looks identifiable."*
2936. **Liability notice in the issue body**: *"Submitter grants a non-revocable license to use this content in the open-forge recipe; the project bears no liability for the submitter's choice to share."*
294
295### When reviewing PRs sourced from issues
296
297Issue-processing sessions must re-scan PR diffs against the same strip-list before merging. If any identifier slipped through, redact in the PR before merge — never merge content with live identifiers.
298
299---
300
301## Processing incoming issues
302
303When an AI coding session is asked to process incoming issues (whether by a maintainer prompt, a scheduled job, or a webhook), apply this workflow:
304
305> **Catalog-growth sources** beyond GitHub issues — public lists / feeds the bot pulls from in priority order — are documented in [`progress/sources.md`](progress/sources.md). The current queue is **selfh.st** (in progress) → **awesome-selfhosted-data** (queued) → **Self-Host Weekly newsletter** (continuous) → **GitHub issues** (continuous). When the active source completes or a new source is added, update `progress/sources.md` to reflect the change.
306
307### 1. Triage
308
309For each open issue without an `applied` / `out-of-scope` / `needs-info` label:
310
311- Identify the template type from the issue body's structured fields. If the issue doesn't follow a template, comment with a pointer to the templates and label `needs-info`.
312- Validate that the issue is in scope per *Is this software in scope?*. Out-of-scope → comment + `out-of-scope` label + close.
313- Otherwise, label `triaged` and proceed to validation.
314
315### 2. Validate against upstream
316
317Apply *Strict doc-verification policy* to every change:
318
319- For `recipe-feedback`: re-fetch the recipe's cited upstream URLs; verify the user's proposed change is consistent with current upstream content. If upstream has drifted in a way that conflicts with the user's report, prefer upstream and explain the discrepancy in the PR.
320- For `software-nomination`: confirm the software passes inclusion criteria; locate upstream's install-method index; do **not** start authoring a recipe until the index is reachable.
321- For `method-proposal`: confirm the cited upstream URL documents the method; if it's community-maintained, it must be flagged per *Community-maintained methods — flagging requirements*.
322
323If validation fails (upstream URL 404s, software is out of scope, methodology is unverifiable), comment on the issue explaining + label `needs-info` or `out-of-scope` as appropriate. Do not author a patch.
324
325### 3. Author the patch
326
327- Apply the change per *Recipe structure (must-have sections)*.
328- Cite the upstream URL at the top of every section per *Strict doc-verification policy*.
329- Flag community-maintained methods with the required ⚠️ blockquote.
330- Re-scan against the *Sanitization principles* strip-list — if any identifier slipped through user-supplied content, redact before drafting.
331- **If your patch touches `CLAUDE.md`, `plugins/open-forge/skills/open-forge/SKILL.md`, or any file under `plugins/open-forge/skills/open-forge/references/`, regenerate the multi-platform distribution bundles**: `./scripts/build-dist.sh all`. Include the regenerated `dist/` files in the same PR. The bundles concatenate canonical sources for non-Claude-Code platforms (Codex / Cursor / Aider / Continue / generic); they drift if not regenerated, which silently breaks those platforms. CI enforces this — see `.github/workflows/dist-bundles.yml`.
332- Bump `plugin.json` `version` per *Versioning + publish flow*.
333- If multiple feedback issues for the same recipe are pending, batch them into a single PR.
334
335### 4. Open the PR
336
337- **Branch naming**: `bot/issue-<N>-<short-slug>` (where `<N>` is the originating issue number).
338- **Commit author**: `Qi Zhang <zhangqi444@gmail.com>` per *Author convention*.
339- **PR body** must cite (a) the originating issue number(s), (b) every upstream URL re-verified, (c) the version bump rationale.
340- After opening, label the issue `in-progress`. After merge, relabel `applied`.
341
342### 5. State-machine via labels
343
344| Label | Meaning |
345|---|---|
346| (none) | New issue, not yet triaged |
347| `triaged` | Identified template type + scope-checked; ready to validate |
348| `in-progress` | A PR is open against this issue |
349| `applied` | PR merged; issue resolved |
350| `needs-info` | Author needs to provide more before processing can continue |
351| `out-of-scope` | Software / request doesn't meet inclusion criteria; closed |
352
353Optionally also: `recipe:<name>`, `tier:1`, `tier:2`, `infra:<cloud>`, `runtime:<runtime>` for filtering.
354
355### 6. Conflicts and ambiguity
356
357- **Contradicting suggestions across issues**: prefer upstream-doc-verified content; cite the upstream URL in the PR explaining which suggestion was chosen and why.
358- **Ambiguous suggestion**: if the issue is unclear about what should change, comment asking for clarification with a deadline (e.g. *"reply within 14 days or this issue will be auto-closed"*) and label `needs-info`.
359- **Idempotency**: never re-process an issue already labeled `applied`. If the same recipe issue resurfaces under a new issue number, treat it as a fresh demand signal (counts toward Tier 2 → Tier 1 graduation per *Two-tier coverage model*).
360
361---
362
363## Companion skills & MCPs
364
365open-forge orchestrates *upstream-blessed* deployment paths. To do that well, recipes are encouraged to depend on companion skills/MCPs as soft dependencies — declared in prose, not enforced. The filter is one question:
366
367> Does this tool help me **drive** an upstream-supported deploy path more reliably?
368
369| Shape | Stance | Examples |
370|---|---|---|
371| **Operators** — read state, query docs, drive existing CLIs more accurately | ✅ Embrace | `awsdocs` MCP, `gcp-docs` MCP, `cloudflare` MCP, GitHub MCP (fetch upstream `docker-compose.yml` / `charts/`), k8s state-query MCPs |
372| **Generators** — author config from scratch | ❌ Avoid by default | `dockerfile-generator`, `k8s-yaml-generator`, `helm-generator`, `terraform-generator`. Only justified when upstream genuinely ships nothing and we deliberately wrap. |
373| **Plain CLIs** | ✅ Default substrate | `docker`, `kubectl`, `helm`, `aws`, `gcloud`, `az`, `gh`, `ssh`, `terraform` |
374
375How to reference companion tooling — **fallback hierarchy**, in order of preference:
376
3771. **Companion skill/MCP**, if available. Name it in SKILL.md / recipe body in prose: *"If the k8s state MCP is available, use it to confirm pod readiness; otherwise parse `kubectl get pods -o json`."* Claude uses it when present, falls back gracefully when not.
3782. **Captured docs in `references/`**, if no skill/MCP exists. Distill the relevant upstream pages (Helm chart values, k8s CRD schema, AWS CLI flags for the specific service) into a focused reference under `references/modules/<topic>.md` or alongside the recipe. Cite the upstream URL as the source of truth — captured docs are a lossy snapshot, the link is the recovery path (principle #6).
3793. **Inline upstream-doc links** as a last resort, when even capture is overkill — let Claude WebFetch them on demand.
380
381Where to declare companion tooling:
382
383- **In recipe frontmatter**, optionally list `companion-skills:` / `companion-mcps:` as documentation (not enforced — no formal deps mechanism in plugin manifests yet).
384- **In `plugins/open-forge/.mcp.json`**, register MCPs the recipes depend on heavily so they install transparently with the plugin. Reserve this for read-only docs/state MCPs; never wrap deployment commands.
385- **For dev work on open-forge itself** (CI, settings audit, plugin packaging): use whatever skills help your local workflow (`gh-fix-ci`, `claude-settings-audit`) — these don't need to ship with the plugin.
386
387### Recommended companion: `garrytan/gstack`
388
389[`garrytan/gstack`](https://github.com/garrytan/gstack) is a Claude Code skill bundle (Garry Tan, MIT) that ships ~30 SDLC slash commands for AI-assisted engineering: `/office-hours` (product interrogation before coding), `/plan-eng-review` (architecture review), `/review` (code review for production bugs), `/qa` (test + regression-suite generation), `/ship` (sync + test + audit + push PR), `/cso` (OWASP Top 10 + STRIDE security audit), `/learn` (persistent project learnings), `/retro` (engineering retrospective), and others.
390
391**Install** (one-shot in any Claude Code session):
392
393```bash
394git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack \
395 && cd ~/.claude/skills/gstack && ./setup
396```
397
398**How its commands map to open-forge work**:
399
400| gstack command | When to use on open-forge |
401|---|---|
402| `/office-hours` | Before authoring a new module (backups, monitoring) or a bundle — interrogate the design before writing code. |
403| `/plan-eng-review` | Before merging a major architectural addition (e.g. multi-platform support, agent-platform support) — catches the kind of cross-cutting issues that slipped past on PR #44 (in-bundle reference paths). |
404| `/review` | On any PR that touches `references/projects/*.md`, `SKILL.md`, or `CLAUDE.md` — production-bug-flavored code review. |
405| `/qa` | After authoring a new recipe — would force first-run-discipline-style verification before claiming Tier 1. |
406| `/ship` | The PR-creation flow this session has been doing manually (sync main → regenerate dist → push → open PR with structured body). |
407| `/cso` | Periodic security audit — credential handling module is the obvious target. |
408| `/learn` | Capture session-level learnings (e.g. *"the bot polls newsletters — check origin/main before authoring duplicate work"*) into a persistent store the next AI session can read. |
409| `/document-release` | Update README + CLAUDE.md + ARCHITECTURE.md to match shipped code — ran manually as PR #45 did. |
410
411Optional but recommended for AI sessions and maintainers working on this repo. Not required — the catalog has been maintained without it. But the workflow patterns it encodes line up cleanly with how PR-authoring actually happens here.
412
413When a recipe is exercised end-to-end and a companion skill/MCP proved necessary — or a captured doc was added to `references/` — record it in the recipe's *Compatible runtimes* or a new *Companion tooling* note alongside upstream doc links. Same first-run discipline applies.
414
415## Recipe structure (must-have sections)
416
417Every `references/projects/<software>.md` should have:
418
419| Section | Purpose |
420|---|---|
421| **Frontmatter** (name + description) | Loaded into context whenever the skill triggers. Keep concise; this is for Claude, not the user. |
422| **Inputs to collect** (table keyed by phase) | Exact prompts, structured-choice options, defaults. So the same recipe is consistent across runs. |
423| **Compatible runtimes** | Which runtime modules this software supports + recommended default |
424| **Phase applicability** | Which of preflight/provision/dns/tls/smtp/inbound/hardening apply or skip |
425| **Per-phase content** | Project-specific commands, config patches, verification checks |
426| **Gotchas (consolidated)** | One-line summaries of every non-obvious thing learned in production. Single source of truth. |
427| **TODO — verify on subsequent deployments** | Open questions to resolve on the next real deploy. Empty = recipe is fully validated. |
428
429`references/runtimes/<name>.md` and `references/infra/<name>.md` mirror this with their own scope (no `Inputs to collect` for infra usually — preflight handles AWS profile/region; infra adds bundle/region-specific bits).
430
431## First-run discipline
432
433When a recipe is exercised end-to-end against a real deployment for the first time:
434
4351. Capture every gotcha that surprised us into the recipe's *Gotchas* section.
4362. Resolve / delete TODO items as they're answered.
4373. Update the deployment state file's phase notes.
4384. Bump `plugin.json` `version` (see *Versioning* below).
4395. Commit.
440
441This is how the recipe stops being a guess and becomes a known-working deployment template. Don't skip it.
442
443The dominant path for first-run discipline is now **user-submitted feedback issues** processed per *Processing incoming issues* — the skill drafts a sanitized issue at the end of each deploy and the user opts in to share. Maintainer-driven deploys (where the maintainer is also the recipe author) still apply for new recipes. Either way, the same five-step capture applies.
444
445## File layout
446
447```
448open-forge/
449├── CLAUDE.md ← you are reading
450├── AGENTS.md ← agents.md-standard landing page; thin pointer to CLAUDE.md
451├── ARCHITECTURE.md ← system shape (actors, data flow, state stores, quality gates) — complement to this file
452├── BRD.md ← project intent (why / who / success / non-goals) — strategic clarity
453├── README.md ← user-facing, lives on GitHub
454├── CHANGELOG.md ← user-visible changes per version (Keep-a-Changelog format; required on every version bump)
455├── LICENSE ← MIT
456├── .claude-plugin/marketplace.json ← marketplace manifest
457├── .github/
458│ ├── ISSUE_TEMPLATE/ ← three issue channels (recipe-feedback, software-nomination, method-proposal)
459│ └── workflows/
460│ ├── dist-bundles.yml ← CI: fail PRs whose dist/ bundles are stale vs canonical sources
461│ └── release.yml ← auto-creates GitHub Release on plugin.json version bump
462├── docs/platforms/ ← per-platform usage guides (Codex / Cursor / Aider / Continue / OpenClaw / Hermes / generic)
463├── dist/ ← regenerated multi-platform distribution bundles (see scripts/build-dist.sh)
464├── progress/ ← bot's state files: selfhst-progress.json + selfhst-software.json + issues-log.json (bot-owned) + sources.md (maintainer-curated source queue)
465├── assets/ ← icon.svg + social-preview.svg
466├── scripts/
467│ └── build-dist.sh ← regenerates dist/ from canonical sources; run when CLAUDE.md / SKILL.md / modules change
468└── plugins/open-forge/
469 ├── .claude-plugin/plugin.json ← plugin manifest (version!)
470 └── skills/open-forge/
471 ├── SKILL.md ← end-user-Claude entrypoint
472 ├── references/
473 │ ├── projects/<name>.md ← software layer (2,200+ Tier 1 verified recipes)
474 │ ├── runtimes/<name>.md ← runtime layer (docker.md, podman.md, native.md, kubernetes.md)
475 │ ├── infra/<name>.md ← infra layer (aws/, azure/, hetzner/, digitalocean/, gcp/, oracle/, paas/, hostinger.md, raspberry-pi.md, macos-vm.md, byo-vps.md, localhost.md)
476 │ ├── modules/<name>.md ← cross-cutting (preflight, dns, tls, smtp providers, inbound forwarders, tunnels, credentials, feedback, backups, monitoring)
477 │ └── bundles/<name>.md ← curated multi-software bundles (recipe-of-recipes; ai-homelab, privacy-stack)
478 └── scripts/ ← deployment-time operational scripts (per-recipe); empty by default
479```
480
481The skill-side `plugins/open-forge/skills/open-forge/scripts/` (deployment-time) stays empty unless something is reused 3+ times across deployments — inline commands in recipes are clearer for one-off use. Distinct from the top-level `scripts/` (build-time tooling for dist/ bundles).
482
483For the **system architecture** (how the catalog grows, who maintains what, how an issue becomes a recipe edit, where state lives), see [`ARCHITECTURE.md`](ARCHITECTURE.md). This file is *policy*; ARCHITECTURE.md is *system shape*.
484
485## Versioning + publish flow
486
487`plugin.json` `version` controls what the Claude Code marketplace fetches.
488
489- **Bump on**: skill description change, new project/runtime/infra, major recipe rewrite, anything that changes user-visible behavior.
490- **Don't bump on**: typo fixes, internal comment cleanups, lint-only changes.
491
492Publish flow (typical path: AI session processing an issue per *Issue-driven contribution model*):
493
4941. Add a `CHANGELOG.md` entry in user-visible terms (Keep-a-Changelog format) under `## [Unreleased]` → move to `## [<version>]` on bump.
4952. Bump `plugin.json` `version`.
4963. Commit and push to `main` (typically as a PR).
4974. `.github/workflows/release.yml` auto-creates a GitHub Release tagged `v<version>` with notes pulled from the matching `CHANGELOG.md` section.
4985. Users run `/plugin marketplace update` in their Claude Code session to pick up the new version.
499
500Maintainer manual edits follow the same flow but skip the issue-tracking labels.
501
502## Author convention
503
504Commits authored as `Qi Zhang <zhangqi444@gmail.com>` — set inline via env vars (`GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`, `GIT_COMMITTER_EMAIL`), **don't write to git config**.
505
506## Refactor (started 2026-04-24, completed 2026-04-26)
507
508Initial state collapsed three axes into linear "Path A/B/C" inside `openclaw.md`, which hid valid combos and biased preflight toward AWS even for non-AWS deployments. Migrated to the 3-layer file layout above. Order:
509
5101. ✅ CLAUDE.md model locked in (this section).
5112. ✅ Preflight refactor — branch on infra choice; only require AWS CLI when infra ∈ AWS.
5123. ✅ Skeleton infra adapters: `infra/aws/lightsail.md` (Bitnami + OpenClaw blueprints share this; the blueprint-vs-Ubuntu split is a project-recipe concern, not a separate adapter), `infra/aws/ec2.md`, `infra/azure/vm.md`, `infra/hetzner/cloud-cx.md`, `infra/digitalocean/droplet.md`, `infra/gcp/compute-engine.md`, `infra/oracle/free-tier-arm.md`, `infra/hostinger.md`, `infra/raspberry-pi.md`, `infra/macos-vm.md`, `infra/byo-vps.md`, `infra/localhost.md`, plus a PaaS family under `infra/paas/`: `fly.md`, `render.md`, `railway.md`, `northflank.md`, `exe-dev.md`.
5134. ✅ Runtime modules: `runtimes/docker.md`, `runtimes/podman.md`, `runtimes/native.md`, `runtimes/kubernetes.md`. Docker + native extracted from openclaw.md Paths B and C; kubernetes added when openclaw upstream's Kustomize-based path was wired in; podman added in v0.8.0.
5145. ✅ Slim down `projects/openclaw.md` — software-layer concerns only; reference runtimes + infra modules for everything else. v0.8.0: corrected the Kubernetes section to be Kustomize-first (matches upstream `scripts/k8s/deploy.sh`); added Podman, ClawDock, Ansible, Nix, and Bun (experimental) sections; combo table now enumerates every upstream-blessed install method documented under `docs.openclaw.ai/install/*`.
5156. ✅ Add `modules/tunnels.md` for localhost public-reach (Cloudflare Tunnel / Tailscale / ngrok).
5167. ✅ Update SKILL.md, README.md support tables and prompts. Bump plugin version (→ 0.8.0).
517
518Path A/B/C terminology retired. Future work tracked in each adapter's *TODO — verify on subsequent deployments* section, not here. Cluster-provisioning adapters (EKS / GKE / AKS / DOKS) are intentionally not in scope — open-forge orchestrates an existing cluster; users own cluster create/delete in their cloud's k8s UI. Cloud-VM adapters and PaaS adapters added in v0.8.0 are documented from upstream docs only — none has been exercised end-to-end yet; first-run discipline (CLAUDE.md § *First-run discipline*) applies as those deployments happen.
519
520## Behavioral guidelines (echoes of bota CLAUDE.md, kept here for autonomy)
521
522- **Think before coding.** State assumptions; ask when uncertain; surface tradeoffs.
523- **Simplicity first.** Minimum recipe content that works; no speculative abstractions.
524- **Surgical changes.** When updating a recipe after a deploy, change only what the deploy taught us. Don't "improve" adjacent sections.
525- **Goal-driven execution.** A recipe edit is "done" when the next deploy can use it without manual fixes.
526- **Documentation updates** (the recipes themselves) are a deliverable of every deployment, not a follow-up.
527
@@ −1 +1 @@
1−# AGENTS.md
1+# CLAUDE.md
22
3−[`agents.md`](https://agents.md) compatibility — this file orients any AI coding agent (Claude Code, Codex, Cursor, Aider, Continue.dev, OpenClaw, Hermes-Agent, or a custom tools-using LLM) that's working *on* the open-forge codebase. End users **using** the open-forge skill to deploy software should look at [SKILL.md](plugins/open-forge/skills/open-forge/SKILL.md) instead.
3+Instructions for any AI coding session working *on* the open-forge plugin (not running it). Different audience from `plugins/open-forge/skills/open-forge/SKILL.md`, which is what an end-user's agent reads to *use* the plugin.
44
5−> **Canonical reference.** This file is intentionally short. The full architectural treatment, strict-doc-verification policy, two-tier coverage model, sanitization rules, and issue-processing workflow live in [**CLAUDE.md**](CLAUDE.md). Read that for the complete picture — AGENTS.md is the agents.md-standard landing page that points at it.
5+> **Also accessible as [`AGENTS.md`](AGENTS.md)** per the [agents.md](https://agents.md) convention. AGENTS.md is a thin landing page that points here; this file is the canonical reference. Tools that look for either filename find their way in.
6+>
7+> **For *system shape* (actors, data flow, state stores, quality gates, cadence) see [`ARCHITECTURE.md`](ARCHITECTURE.md).** This file is the *policy* (what's in scope, strict-doc rules, sanitization principles, processing workflow); ARCHITECTURE.md is how the policy is operationalized as a maintenance system.
8+>
9+> **For *intent* — why the project exists, who it's for, what success looks like, what we're explicitly not building — see [`BRD.md`](BRD.md).** When a strategic decision feels off (or when a recipe-authoring choice has policy ambiguity), check BRD.md before re-litigating.
610
7−## What this project is
11+## What is open-forge
812
9−`open-forge` is a guided self-hosting **skill** distributed via Claude Code's plugin marketplace and adapted for 6+ other AI platforms. It walks users from *"I have a cloud account and a domain"* to *"working app at https://my.domain"* via a phased workflow (preflight → provision → dns → tls → smtp → inbound → hardening → feedback) using 2,200+ verified recipes plus curated bundles for goal-shaped requests (AI homelab, privacy stack) plus a live-derived fallback for the long tail.
13+A Claude Code plugin/skill that turns "read a README, copy-paste 30 lines of bash, debug for hours" into a guided chat where Claude executes everything via the user's local CLI tools and the user only makes choices.
1014
11−This **isn't a typical software repo** — it's a library of platform-agnostic markdown recipes + a thin Bash build script. There's no compiled artifact, no test suite, no lint config. The "build" is regenerating distribution bundles from canonical sources.
15+## Architecture — 3 layers, asked in 3 questions
1216
13−## Working on this repo — the rules
17+A deployment is a tuple of three independent axes, asked in this order:
1418
15−Per [CLAUDE.md](CLAUDE.md):
19+| # | Question | Layer | Examples |
20+|---|---|---|---|
21+| 1 | **What** to host? | software | OpenClaw, Ghost, Mastodon, Vaultwarden, Nextcloud |
22+| 2 | **Where** to host? | infra (cloud or local) | AWS / Hetzner / DigitalOcean / GCP / Azure / bring-your-own-VPS / **localhost** |
23+| 3 | **How** to host (within that cloud)? | infra-service + runtime | AWS: Lightsail blueprint, Lightsail Ubuntu + Docker, EC2 + native, EKS, ECS Fargate. Hetzner: Cloud CX + Docker, Cloud CX + native. localhost: Docker Desktop, native. |
1624
17−1. **No human PRs — issues only.** Catalog evolves through GitHub issues processed by AI sessions. See [`.github/ISSUE_TEMPLATE/`](.github/ISSUE_TEMPLATE/) for the three input channels (recipe-feedback, software-nomination, method-proposal). Direct PRs are discouraged; if you submit one, the strict-doc policy still applies.
18−2. **Strict-doc-verification policy.** Every install method in every recipe must cite an upstream URL (`> **Source:** <url>`). Community-maintained methods open with the required ⚠️ blockquote. The README is necessary but **not sufficient** — also read the upstream docs site, repo `docs/install/` tree, and wiki. If upstream-doc fetch fails, **stop**; do not write speculative content. Full rules in [CLAUDE.md § Strict doc-verification policy](CLAUDE.md#strict-doc-verification-policy-mandatory-before-writing-any-recipe).
19−3. **Sanitization principles.** User-shared content (deploy logs, gotchas, error output) must be stripped of identifiers (domains, IPs, SSH keys, API keys, AWS account IDs, emails) before being merged into recipes or posted to GitHub issues. Full strip-list with regex patterns in [CLAUDE.md § Sanitization principles](CLAUDE.md#sanitization-principles).
20−4. **Two-tier coverage model.** Tier 1 = verified recipes in `references/projects/`. Tier 2 = live-derived from upstream docs at runtime for software not yet in the catalog. Promotion criteria in [CLAUDE.md § Two-tier coverage model](CLAUDE.md#two-tier-coverage-model).
21−5. **In-scope test.** Before adding a recipe: deployable service / static-site generator / CLI agent / AI inference server / CI runner / storage backend → ✅. Library / desktop app / SaaS-only → ❌. Decision rule + edge-case table in [CLAUDE.md § Is this software in scope?](CLAUDE.md#is-this-software-in-scope).
25+The third question is *dynamically generated* from (software, cloud) — different clouds expose different compute services, and some software has vendor-bundled blueprints on specific clouds.
2226
23−## Build / test / lint
27+**Some infra services bundle the runtime** — EKS → Kubernetes, Lightsail OpenClaw blueprint → vendor's pre-baked install. In those cases the "runtime" question is not asked separately. **Other services give runtime choice** — EC2, plain VPS, localhost — there we ask Docker vs native vs k3s.
2428
25−There is no traditional build / test / lint pipeline. The single build artifact is the multi-platform distribution bundles under `dist/`:
29+**Reusability is the test.** "Install Docker + run docker-compose" is the same on Lightsail Ubuntu, Hetzner CX-line, a DO droplet, and a localhost — write it once in the runtime layer, reference from every project. "Install k3s" is the same across clouds — write it once. Project recipes should be 80% software-specific concerns and contain *no* per-runtime install commands beyond a one-line link.
2630
27−```bash
28−./scripts/build-dist.sh all # regenerate bundles for all 7 platforms
29−./scripts/build-dist.sh codex # just Codex
30−./scripts/build-dist.sh openclaw # just OpenClaw
31+### File layout for the 3 layers
32+
3133 ```
34+references/
35+├── projects/<sw>.md # software layer (thin)
36+├── infra/
37+│ ├── aws/
38+│ │ ├── lightsail-blueprint.md # vendor-bundled, software-specific
39+│ │ ├── lightsail-ubuntu.md # Lightsail as a plain VM
40+│ │ ├── ec2.md
41+│ │ ├── eks.md
42+│ │ └── ecs-fargate.md
43+│ ├── hetzner/cloud-cx.md
44+│ ├── digitalocean/droplet.md
45+│ ├── gcp/compute-engine.md
46+│ ├── byo-vps.md # user provides any Linux VPS, Claude SSH-es in
47+│ └── localhost.md # user's own machine, Claude runs commands directly
48+├── runtimes/
49+│ ├── docker.md # reusable wherever Docker works
50+│ ├── native.md # native installer (curl/apt)
51+│ └── kubernetes.md # reusable across EKS/GKE/AKS/k3s
52+└── modules/ # cross-cutting (preflight, dns, tls, smtp providers, inbound forwarders, tunnels, backups, monitoring)
53+```
3254
33−**Required after touching any of:** `CLAUDE.md`, `plugins/open-forge/skills/open-forge/SKILL.md`, `plugins/open-forge/skills/open-forge/references/modules/*.md`. The bundles concatenate these files; they drift if not regenerated, which silently breaks non-Claude-Code platforms.
55+`localhost.md` is a first-class infra — for many projects (especially OpenClaw), running locally is the default upstream path. Same conversational UX as a cloud deploy; differences are: no SSH (Claude runs commands directly), no provisioning, public reach via tunnel (`references/modules/tunnels.md`).
3456
35−CI enforces this — see [`.github/workflows/dist-bundles.yml`](.github/workflows/dist-bundles.yml). If the `dist-bundles-up-to-date` check fails on your PR, the fix is always: run `./scripts/build-dist.sh all` from the repo root, commit the changes, push.
57+### A fourth orchestration layer — bundles
3658
37−## Versioning
59+Above software / infra / runtime sits an optional **bundle** layer (`references/bundles/`). A bundle is a *recipe-of-recipes* — it pairs commonly-co-deployed software for goal-shaped user requests (*"set up an AI homelab"*) and ships the cross-software wiring (env vars / DNS / ports between constituents). Bundles don't replace single-recipe routing; they're an additional entry point for goal-shaped intents.
3860
39−`plugins/open-forge/.claude-plugin/plugin.json` `version` controls what the Claude Code marketplace fetches.
61+Per *Tier 2 → Tier 1 graduation criteria* below, bundles aren't speculative authoring — they orchestrate **existing Tier 1 recipes** only. If a constituent recipe gets demoted, the bundle goes with it. New bundles get added when 3+ users (or one repeat user) ask for the same combination. Current bundles: `bundles/ai-homelab.md` (Ollama + Open WebUI + AnythingLLM + Aider) and `bundles/privacy-stack.md` (Pi-hole + Vaultwarden + Headscale OR wg-easy).
4062
41−- **Bump on**: skill description change, new project / runtime / infra / module, major recipe rewrite, anything user-visible.
42−- **Don't bump on**: typo fixes, internal cleanups, lint-only changes.
63+## Is this software in scope?
4364
44−## Author convention
65+open-forge is for **deployable self-hosted services**. Use these criteria when deciding whether a piece of software belongs as a Tier 1 recipe (see *Two-tier coverage model* below).
4566
46−Commits authored as `Qi Zhang <zhangqi444@gmail.com>` — set inline via env vars (`GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`, `GIT_COMMITTER_EMAIL`). Never write to `git config`.
67+### Inclusion criteria — recipe is in scope when ALL are true
4768
48−## Recommended companion skill — `garrytan/gstack`
69+1. **Software runs as a deployed service or is served from a host the user owns**: long-running daemon, scheduled job, web service, API, CLI agent, or static asset published to a host.
70+2. **Source code or binaries are user-installable on infrastructure they control**: cloud VM, VPS, k3s cluster, or localhost. Paid AMIs / vendor stacks (Bitnami, Dify Premium, etc.) count — closed-source SaaS-only does not.
71+3. **At least one upstream-documented install method or canonical install artifact in-repo** exists, so the strict-doc-policy below has something to verify against.
4972
50−If you're a Claude Code session working on this repo, install [`garrytan/gstack`](https://github.com/garrytan/gstack) — Garry Tan's SDLC slash-command bundle. Its `/review`, `/qa`, `/ship`, `/cso`, `/learn`, and `/plan-eng-review` commands map directly onto the maintenance workflows used here. Install:
73+### Exclusion criteria — out of scope
5174
75+- **Pure libraries / SDKs / packages** that you `import` or call (Unsloth, requests, lodash). No deployment surface.
76+- **Desktop / mobile end-user apps** with no self-hosted server side (Slack desktop, VS Code, Discord client).
77+- **SaaS / managed-only products** with no self-host distribution (Notion, Linear, Figma).
78+- **Dev-only tooling that runs ephemerally on a developer machine** and is never deployed (Storybook *dev* mode, Vite dev server, REPLs).
79+
80+### Edge cases — borderline classes
81+
82+| Class | Verdict | Recipe shape |
83+|---|---|---|
84+| **Static-site generators** (Hugo, Jekyll, Docusaurus, Storybook in production-preview mode) | ✅ in scope | Thin: `<sg> build` → static dir → deploy via a static-host module (nginx / S3+CDN / Pages). The SG-specific bit is build config, theme path, content tree. |
85+| **CLI agents** (Aider, OpenClaw, Hermes-Agent) | ✅ in scope | Install on a host, run as daemon or interactive CLI. Standard recipe shape. |
86+| **AI inference servers** (vLLM, Ollama, TGI) | ✅ in scope | Deployed services exposing HTTP APIs. Standard recipe shape. |
87+| **AI training libraries** (Unsloth, axolotl, transformers) | ❌ out of scope | Libraries called from training scripts, not deployed services. If a "training environments" track ever exists, it's a separate category — not project recipes under `references/projects/`. |
88+| **CI runners** (GitHub Actions self-hosted, Buildkite agent) | ✅ in scope | Long-running daemon attached to a control plane. Standard recipe shape. |
89+| **Standalone databases** (Postgres, ClickHouse, Redis) | ⚠️ borderline | Useful but usually a dependency of another recipe rather than a deployment goal. Document as a supporting service inside the consuming recipe; only write a standalone recipe when there's clear demand. |
90+| **Storage backends** (MinIO, SeaweedFS, Garage) | ✅ in scope | Self-hostable services with HTTP APIs. Standard recipe shape. |
91+
92+### When in doubt
93+
94+Ask: *"Would the user need open-forge to walk them through provisioning + DNS + TLS + ongoing lifecycle for this?"* If yes, write a recipe. If no (e.g. they'd just `pip install` it inside their own scripts), it's out of scope — or fall back to Tier 2 (below) for one-off requests.
95+
96+## Operating principles
97+
98+1. **Do more, ask less. Non-tech-friendly.** Default to autonomous execution. Only prompt the user for things only they can decide or provide: credentials, opinionated choices, things that touch their accounts at other companies. Hide everything Claude can figure out from the recipe.
99+2. **Towards production-ready architecture.** Even single-node hobby deploys should be on a path to backups, monitoring, TLS, key rotation, OS updates, and least-privilege firewalls. Don't write recipes that "work" but leave the system one outage away from data loss.
100+3. **Security in mind.** Treat tokens/keys as toxic — never log them, rotate after chat exposure, prefer fragment URLs over query strings. Default firewalls to closed; open ports explicitly. Default to SSH key auth; never password. Let's Encrypt for any public endpoint. Sandbox agent tool execution where the runtime supports it.
101+4. **One question at a time.** Use `AskUserQuestion` for structured choices. Reserve free-text for credentials and identifiers (domain names, emails). No upfront questionnaires.
102+5. **Auto-install with confirmation, never silently.** If `jq` or `aws` is missing, propose the install command, get one-line approval, then run.
103+6. **Reference upstream docs; don't replace them.** Recipes condense and translate upstream documentation into Claude-actionable steps — they aren't the source of truth for the product itself. Always link the upstream pages we summarized (e.g. `docs.openclaw.ai/install/docker`, AWS Lightsail user guide, Bitnami docs). Reasons: (a) users can verify what we condensed, (b) when upstream drifts our recipe goes stale fast and the link is the recovery path, (c) credit where due. **See *Strict doc-verification policy* below — every install method documented by upstream must have its own recipe section, verified against upstream before being written.**
104+7. **Don't invent — interface.** open-forge is a chat-friendly interface to existing tools. Claude is the orchestrator; the user's existing software stack (AWS CLI, Docker, openclaw, ssh, gh, registrar UIs) is the substrate. **Do not** build custom DSLs, YAML schemas, CLI tools, deployment managers, or wrappers around upstream tools. **Do not** reimplement what an upstream tool already does (e.g. don't rebuild `openclaw onboard`'s prompts in chat — call the command). The state file is a thin orchestration helper for resume, nothing more. *Caveat:* "don't invent" applies to **fabricating a deployment path the upstream doesn't support** (e.g. authoring a Helm chart for a project that has no chart). It does **not** mean "no tooling." If upstream supports Docker / k8s / Helm / Terraform, lean on every skill and MCP that helps you orchestrate those paths well — see *Companion skills & MCPs* below.
105+
106+## Credential handling (expanded from Operating Principle #3)
107+
108+Pasting raw credentials into Claude Code is risky — secrets enter session history, may be relayed via MCP servers, and could appear in shared transcripts. The skill must offer safer alternatives **first** and only fall back to direct paste with explicit risk acknowledgement.
109+
110+### The five patterns (priority order)
111+
112+| # | Pattern | When to suggest |
113+|---|---|---|
114+| 1 | **Local file path** — user gives skill a path; skill `cat`s it | Personal-use API keys; user already has a `.env` or `.secrets` file |
115+| 2 | **Env var name** — user pre-exports the secret; skill reads `$<NAME>` | Shell users with secrets in `.envrc` / `.bashrc` |
116+| 3 | **Cloud-CLI session** — user runs `<provider> login` ahead of time; skill uses the resulting profile / session | Default for AWS, GCP, Azure, GitHub, DigitalOcean, Hetzner, Cloudflare |
117+| 4 | **Secrets-manager reference** — user gives skill a `op://` / `bw://` / `vault://` reference; skill calls the matching CLI just-in-time | Users with proper secret management (1Password, Bitwarden, Vault, AWS Secrets Manager, GCP Secret Manager, `pass`) |
118+| 5 | **Direct chat paste** — last resort, requires risk acknowledgement | When patterns 1-4 don't apply; user explicitly opts in |
119+
120+### Hard rules
121+
122+- **Always offer the five patterns** when asking for any sensitive input. Don't silently accept a paste; don't assume Claude Code is a vault.
123+- **Surface the risk** before accepting a direct paste: *"the key will live in this session's history; rotate after deploy completes."*
124+- **Never accept SSH key contents.** Always ask for the key file *path* (skill uses `ssh -i <path>`); never the key material itself in chat.
125+- **Validate before proceeding**: `test -r <path>` for file paths; `test -n "$<VAR>"` for env vars; smoke-command for cloud-CLI sessions and secrets-manager refs.
126+- **Refuse files with permissions wider than 600**; offer to `chmod 600` first.
127+- **Detect accidental pastes** (regex for `re_*`, `sk-*`, `AKIA*`, etc. in a prompt that expected a path) and stop the user before the secret commits to chat.
128+- **End-of-deploy rotation reminder** if the user pasted any secret directly during the deploy: list each pasted credential + the provider's dashboard URL; recommend rotating now that the deploy is done.
129+
130+The full pattern catalog with skill prompt templates, per-credential-class recommendations, and failure-mode handling lives in [`plugins/open-forge/skills/open-forge/references/modules/credentials.md`](plugins/open-forge/skills/open-forge/references/modules/credentials.md).
131+
132+## Strict doc-verification policy (mandatory before writing any recipe)
133+
134+Recipes are condensations of upstream docs; condensing what we haven't read is speculation. Past failures (the v0.7.0 Helm chart claim sourced from a search snippet, the v0.6.0 OpenClaw "every blessed path" claim that was 4 of 17 because we trusted the README's enumeration) traced back to this. The policy:
135+
136+### Before writing or expanding any project / infra recipe
137+
138+1. **Read the upstream README verbatim.** Not summarized — the actual README. Note: the README is necessary but **not sufficient** — many projects' READMEs are deliberately minimal and point at a separate docs site for install methods.
139+2. **Locate the upstream install-method index.** Typically:
140+ - The project's docs site (`docs.PROJECT.ai`, `PROJECT.com/docs`, `PROJECT.github.io`, etc.).
141+ - The repo's `docs/install/` or `website/docs/getting-started/` tree.
142+ - The repo's wiki (often a separate `<repo>.wiki.git` clone).
143+3. **Enumerate every method documented under that index.** Include:
144+ - First-party install scripts (`install.sh`, `install.ps1`, vendor blueprints).
145+ - First-party Docker / Compose / Kubernetes / Helm support.
146+ - First-party package-manager support (Homebrew, Nix, Pacman, etc.).
147+ - First-party PaaS templates (`fly.toml`, `render.yaml`, Railway / Zeabur / Sealos one-click buttons published by upstream).
148+ - First-party cloud templates (Terraform / CDK / Computing Nest published by upstream).
149+4. **Read the canonical install artifacts in the repo:** `docker-compose.yml`, `Dockerfile`, `flake.nix`, the project's primary config-file example. These often surface details the docs gloss over (service inventory, env-var matrix).
150+5. **Write one section per documented method.** No merging, no skipping. Each section's first line cites the upstream URL it's derived from.
151+
152+### What counts as "official"
153+
154+| Source | Official? |
155+|---|---|
156+| Upstream's own README | ✅ |
157+| Upstream's own docs site (linked from README) | ✅ |
158+| Upstream's repo `docs/` or `website/` tree | ✅ |
159+| Upstream's repo wiki | ✅ |
160+| Upstream-published PaaS deploy buttons (Railway/Render/Fly/etc.) where the manifest lives in the upstream repo | ✅ |
161+| Community-maintained Docker images / Helm charts when upstream ships none | ⚠️ Allowed but **must be flagged** as "community-maintained, verify source"; recipe lists multiple options (most-active first), doesn't pick a winner |
162+| Anything else (third-party blogs, search snippets, my training data) | ❌ Not allowed as the basis for a section. If upstream ships no path for X, do not invent one. |
163+
164+### When upstream-doc fetch fails
165+
166+- WebFetch rate-limited / 403 / 404 → try `raw.githubusercontent.com/<org>/<repo>/<branch>/<path>` for repo content.
167+- Wiki page WebFetch fails → `git clone https://github.com/<org>/<repo>.wiki.git` and read locally.
168+- All fetch paths fail → **stop**. Do not write speculative content. Either: (a) ask the user to paste relevant doc text, (b) wait until access is restored, or (c) write only the sections for methods we *did* read and note in the recipe's TODO that the rest is pending verification.
169+
170+### Community-maintained methods — flagging requirements
171+
172+When a recipe documents a method upstream doesn't ship (e.g. A1111 + ComfyUI Docker, Helm charts for many projects), the section MUST:
173+
174+1. Open with an explicit "community-maintained" note in a blockquote.
175+2. List **multiple** options when they exist (most-active first; reference upstream README's pointer if upstream lists them).
176+3. Frame commands as "illustrative — verify the README at the version you pull"; never present community-chart `--set` values as authoritative.
177+4. Document the gap in the recipe's TODO section: "Verify which community option is most actively maintained at first-deploy time."
178+
179+### Retroactive application
180+
181+When this policy is added (or strengthened), every existing recipe must be re-verified against its upstream docs index. If the verification surfaces a missing method, file it in that recipe's TODO, write the missing section, and bump the plugin version.
182+
183+### When in doubt
184+
185+Ask the user whether to pause for verification or accept the README's enumeration. Don't silently downgrade thoroughness.
186+
187+---
188+
189+## Two-tier coverage model
190+
191+open-forge ships a finite catalogue of verified recipes (Tier 1) plus a documented fallback for everything else (Tier 2). Both tiers obey the strict-doc-policy above; the difference is *when* the verification happens.
192+
193+### Tier 1 — verified recipes (the catalogue)
194+
195+The current set under `references/projects/`. Authored ahead of time, audited against upstream docs, kept current via the first-run discipline + version bumps. **Quality bar:**
196+
197+- Every install method has a `> **Source:** <upstream URL>` line at the top of its section.
198+- Community-maintained methods open with the required ⚠️ blockquote per *Community-maintained methods — flagging requirements*.
199+- Gotchas captured from real deploys; TODOs track unresolved verifications.
200+- Plugin version bumped on each user-visible change.
201+
202+### Tier 2 — derived live from upstream docs
203+
204+When a user asks for software that has no Tier 1 recipe, the skill **falls back** instead of refusing:
205+
206+1. **Announce the fallback in one sentence**: *"This software isn't in our verified recipe set — I'll fetch upstream docs live and reuse the runtime / infra modules. Treat my output as best-effort, not authoritative."*
207+2. **Apply the strict-doc-policy on the fly** — same rules as Tier 1:
208+ - Read upstream README via `WebFetch`. If 403/404, fall back to `raw.githubusercontent.com` paths and/or `git clone` the docs repo locally.
209+ - Locate the upstream install-method index (docs site, repo `docs/install/` tree, wiki).
210+ - Enumerate methods from upstream — **do not invent**. If fetches fail, stop and tell the user; never speculate to fill a gap.
211+ - Read canonical install artifacts (`Dockerfile`, `docker-compose.yml`, `helm/`, `flake.nix`).
212+3. **Reuse runtime + infra + cross-cutting modules** under `references/runtimes/`, `references/infra/`, `references/modules/` for all the reusable parts (Docker install, k8s prereqs, VM provisioning, DNS, TLS, SMTP). Tier 2 is mostly *software-specific* on top of those — same shape as Tier 1, just authored at request time.
213+4. **Cite every upstream URL** the same way Tier 1 does.
214+5. **Offer to capture the result** as a new Tier 1 recipe when the deploy succeeds — that's how the catalogue grows. The captured recipe must still go through first-run discipline before claiming Tier 1 status.
215+
216+### Routing
217+
218+The skill checks Tier 1 first by name match against `references/projects/*.md`. If no match, fall back to Tier 2 with the announcement above. **Never silently mix tiers** — the user should always know which tier they're in, since the verification depth differs.
219+
220+### Quality boundary
221+
222+Tier 2 output is **best-effort, not authoritative.** It will hallucinate at the edges of upstream docs we couldn't fetch; it skips the iterative refinement that Tier 1 recipes get from real deploys. Tell the user this. They're trading verification depth for coverage breadth.
223+
224+### Tier 2 → Tier 1 graduation criteria
225+
226+The catalogue grows demand-driven, not by guess. Promote a Tier 2 deploy to a Tier 1 recipe when ANY of:
227+
228+1. **3+ feedback issues** for the same software (demand signal — see *Issue-driven contribution model*).
229+2. **Same user has deployed it 3+ times** and asks for first-run discipline applied.
230+3. **A Tier 2 deploy surfaced a non-obvious gotcha** that's likely to bite the next person — capture the gotcha as a recipe even if demand is small (one-shot promotion is allowed when the value is in the captured knowledge).
231+4. **A maintainer chooses to deploy the software themselves** (sunk cost is acceptable).
232+
233+Don't author Tier 1 recipes speculatively from a "popular self-host" list — without a real demand signal, the compounding effect can't kick in and the upfront cost goes to waste.
234+
235+---
236+
237+## Issue-driven contribution model
238+
239+The catalogue evolves through GitHub issues, not direct human PRs. AI coding sessions (whether triggered by a maintainer running this skill, by a scheduled job, or by a webhook) read incoming issues, verify them against upstream docs per *Strict doc-verification policy*, and author patches.
240+
241+### Three input channels
242+
243+GitHub issue templates under `.github/ISSUE_TEMPLATE/` define the structured input:
244+
245+| Template | When to use | Filed by |
246+|---|---|---|
247+| `recipe-feedback.yml` | A user deployed via the skill and wants to suggest recipe edits (gotchas captured, install steps that surprised them, sections that were wrong/outdated). The skill drafts these automatically at the end of a deploy. | End user (skill-assisted) |
248+| `software-nomination.yml` | A user wants software added to the Tier 1 catalogue. Must include rationale + upstream URL + the user's intended deploy combo. | End user |
249+| `method-proposal.yml` | A user knows an upstream-supported install method that an existing recipe doesn't cover. Must include the upstream URL where the method is documented. | End user |
250+
251+A blank-issue / off-template issue is treated as a request for routing — close politely with a pointer to the templates.
252+
253+### Why issues, not PRs
254+
255+- **Sanitization happens at submission time.** The skill (or a careful manual filer) redacts identifiers before posting; the issue templates encode the structure. PRs from random users could include credentials in commit history that can't be cleanly removed.
256+- **Verification happens centrally.** Every change is re-verified against upstream by the AI session that processes the issue, not trusted because someone filed a PR.
257+- **Demand signal lives in the issue stream.** Issues with the most thumbs-up / cross-linking / repeat filings are the demand signal that drives Tier 2 → Tier 1 graduation.
258+
259+### Direct human PRs
260+
261+Discouraged. If a maintainer writes a PR by hand, it's still subject to the strict-doc-policy and recipe-structure rules — the issue model is the documented contribution path.
262+
263+---
264+
265+## Sanitization principles
266+
267+User-shared content (deployment logs, gotchas, error output) routinely contains identifiers that **must not** end up in the public repo. Both the skill (when drafting issue content) and any session reviewing user-supplied content (when accepting a PR sourced from an issue) must apply these rules.
268+
269+### Always strip
270+
271+| Class | Replace with |
272+|---|---|
273+| Domain names (apex / canonical / admin) | `${CANONICAL_HOST}` / `${APEX}` / `${ADMIN_DOMAIN}` |
274+| IP addresses (public + private + IPv6) | `${PUBLIC_IP}` / `${PRIVATE_IP}` |
275+| SSH key paths and contents | `${KEY_PATH}` / `<REDACTED-SSH-KEY>` |
276+| API keys and bearer tokens (regex: `re_[A-Za-z0-9_]+`, `SG\.[A-Za-z0-9._-]+`, `sk-[A-Za-z0-9]+`, `xox[bp]-[A-Za-z0-9-]+`, `ghp_[A-Za-z0-9]+`, AWS access keys `AKIA[0-9A-Z]{16}` + secret `[A-Za-z0-9/+=]{40}`, GCP service-account JSON, generic `Bearer [A-Za-z0-9._-]{20,}`) | `<REDACTED>` |
277+| AWS account IDs (12 consecutive digits in AWS context) | `${AWS_ACCOUNT}` |
278+| AWS profile names | `${AWS_PROFILE}` |
279+| Email addresses (LE email, SMTP from-address, user identity) | `${EMAIL}` |
280+| State-file contents from `~/.open-forge/deployments/<name>.yaml` | Reference the file by name only, never paste contents |
281+| Hostnames embedded in URLs that include the user's domain | `https://${CANONICAL_HOST}/path` |
282+| Anything from the user's clipboard / env vars they pasted into chat | `<REDACTED>` |
283+
284+### Multi-step consent (no auto-post, ever)
285+
286+The skill flow when posting feedback to GitHub:
287+
288+1. **Opt-in prompt** — *"Want to share what you learned?"* User must explicitly opt in.
289+2. **Show the redacted draft in chat** — full text, before any submission attempt.
290+3. **Confirm post?** — explicit "yes" required.
291+4. **If user edits the draft**, re-show + re-confirm before submitting.
292+5. **Standing reminder text** in the prompt: *"GitHub issues are public and permanent. Once posted, this can't be unposted. Review every line; edit if anything looks identifiable."*
293+6. **Liability notice in the issue body**: *"Submitter grants a non-revocable license to use this content in the open-forge recipe; the project bears no liability for the submitter's choice to share."*
294+
295+### When reviewing PRs sourced from issues
296+
297+Issue-processing sessions must re-scan PR diffs against the same strip-list before merging. If any identifier slipped through, redact in the PR before merge — never merge content with live identifiers.
298+
299+---
300+
301+## Processing incoming issues
302+
303+When an AI coding session is asked to process incoming issues (whether by a maintainer prompt, a scheduled job, or a webhook), apply this workflow:
304+
305+> **Catalog-growth sources** beyond GitHub issues — public lists / feeds the bot pulls from in priority order — are documented in [`progress/sources.md`](progress/sources.md). The current queue is **selfh.st** (in progress) → **awesome-selfhosted-data** (queued) → **Self-Host Weekly newsletter** (continuous) → **GitHub issues** (continuous). When the active source completes or a new source is added, update `progress/sources.md` to reflect the change.
306+
307+### 1. Triage
308+
309+For each open issue without an `applied` / `out-of-scope` / `needs-info` label:
310+
311+- Identify the template type from the issue body's structured fields. If the issue doesn't follow a template, comment with a pointer to the templates and label `needs-info`.
312+- Validate that the issue is in scope per *Is this software in scope?*. Out-of-scope → comment + `out-of-scope` label + close.
313+- Otherwise, label `triaged` and proceed to validation.
314+
315+### 2. Validate against upstream
316+
317+Apply *Strict doc-verification policy* to every change:
318+
319+- For `recipe-feedback`: re-fetch the recipe's cited upstream URLs; verify the user's proposed change is consistent with current upstream content. If upstream has drifted in a way that conflicts with the user's report, prefer upstream and explain the discrepancy in the PR.
320+- For `software-nomination`: confirm the software passes inclusion criteria; locate upstream's install-method index; do **not** start authoring a recipe until the index is reachable.
321+- For `method-proposal`: confirm the cited upstream URL documents the method; if it's community-maintained, it must be flagged per *Community-maintained methods — flagging requirements*.
322+
323+If validation fails (upstream URL 404s, software is out of scope, methodology is unverifiable), comment on the issue explaining + label `needs-info` or `out-of-scope` as appropriate. Do not author a patch.
324+
325+### 3. Author the patch
326+
327+- Apply the change per *Recipe structure (must-have sections)*.
328+- Cite the upstream URL at the top of every section per *Strict doc-verification policy*.
329+- Flag community-maintained methods with the required ⚠️ blockquote.
330+- Re-scan against the *Sanitization principles* strip-list — if any identifier slipped through user-supplied content, redact before drafting.
331+- **If your patch touches `CLAUDE.md`, `plugins/open-forge/skills/open-forge/SKILL.md`, or any file under `plugins/open-forge/skills/open-forge/references/`, regenerate the multi-platform distribution bundles**: `./scripts/build-dist.sh all`. Include the regenerated `dist/` files in the same PR. The bundles concatenate canonical sources for non-Claude-Code platforms (Codex / Cursor / Aider / Continue / generic); they drift if not regenerated, which silently breaks those platforms. CI enforces this — see `.github/workflows/dist-bundles.yml`.
332+- Bump `plugin.json` `version` per *Versioning + publish flow*.
333+- If multiple feedback issues for the same recipe are pending, batch them into a single PR.
334+
335+### 4. Open the PR
336+
337+- **Branch naming**: `bot/issue-<N>-<short-slug>` (where `<N>` is the originating issue number).
338+- **Commit author**: `Qi Zhang <zhangqi444@gmail.com>` per *Author convention*.
339+- **PR body** must cite (a) the originating issue number(s), (b) every upstream URL re-verified, (c) the version bump rationale.
340+- After opening, label the issue `in-progress`. After merge, relabel `applied`.
341+
342+### 5. State-machine via labels
343+
344+| Label | Meaning |
345+|---|---|
346+| (none) | New issue, not yet triaged |
347+| `triaged` | Identified template type + scope-checked; ready to validate |
348+| `in-progress` | A PR is open against this issue |
349+| `applied` | PR merged; issue resolved |
350+| `needs-info` | Author needs to provide more before processing can continue |
351+| `out-of-scope` | Software / request doesn't meet inclusion criteria; closed |
352+
353+Optionally also: `recipe:<name>`, `tier:1`, `tier:2`, `infra:<cloud>`, `runtime:<runtime>` for filtering.
354+
355+### 6. Conflicts and ambiguity
356+
357+- **Contradicting suggestions across issues**: prefer upstream-doc-verified content; cite the upstream URL in the PR explaining which suggestion was chosen and why.
358+- **Ambiguous suggestion**: if the issue is unclear about what should change, comment asking for clarification with a deadline (e.g. *"reply within 14 days or this issue will be auto-closed"*) and label `needs-info`.
359+- **Idempotency**: never re-process an issue already labeled `applied`. If the same recipe issue resurfaces under a new issue number, treat it as a fresh demand signal (counts toward Tier 2 → Tier 1 graduation per *Two-tier coverage model*).
360+
361+---
362+
363+## Companion skills & MCPs
364+
365+open-forge orchestrates *upstream-blessed* deployment paths. To do that well, recipes are encouraged to depend on companion skills/MCPs as soft dependencies — declared in prose, not enforced. The filter is one question:
366+
367+> Does this tool help me **drive** an upstream-supported deploy path more reliably?
368+
369+| Shape | Stance | Examples |
370+|---|---|---|
371+| **Operators** — read state, query docs, drive existing CLIs more accurately | ✅ Embrace | `awsdocs` MCP, `gcp-docs` MCP, `cloudflare` MCP, GitHub MCP (fetch upstream `docker-compose.yml` / `charts/`), k8s state-query MCPs |
372+| **Generators** — author config from scratch | ❌ Avoid by default | `dockerfile-generator`, `k8s-yaml-generator`, `helm-generator`, `terraform-generator`. Only justified when upstream genuinely ships nothing and we deliberately wrap. |
373+| **Plain CLIs** | ✅ Default substrate | `docker`, `kubectl`, `helm`, `aws`, `gcloud`, `az`, `gh`, `ssh`, `terraform` |
374+
375+How to reference companion tooling — **fallback hierarchy**, in order of preference:
376+
377+1. **Companion skill/MCP**, if available. Name it in SKILL.md / recipe body in prose: *"If the k8s state MCP is available, use it to confirm pod readiness; otherwise parse `kubectl get pods -o json`."* Claude uses it when present, falls back gracefully when not.
378+2. **Captured docs in `references/`**, if no skill/MCP exists. Distill the relevant upstream pages (Helm chart values, k8s CRD schema, AWS CLI flags for the specific service) into a focused reference under `references/modules/<topic>.md` or alongside the recipe. Cite the upstream URL as the source of truth — captured docs are a lossy snapshot, the link is the recovery path (principle #6).
379+3. **Inline upstream-doc links** as a last resort, when even capture is overkill — let Claude WebFetch them on demand.
380+
381+Where to declare companion tooling:
382+
383+- **In recipe frontmatter**, optionally list `companion-skills:` / `companion-mcps:` as documentation (not enforced — no formal deps mechanism in plugin manifests yet).
384+- **In `plugins/open-forge/.mcp.json`**, register MCPs the recipes depend on heavily so they install transparently with the plugin. Reserve this for read-only docs/state MCPs; never wrap deployment commands.
385+- **For dev work on open-forge itself** (CI, settings audit, plugin packaging): use whatever skills help your local workflow (`gh-fix-ci`, `claude-settings-audit`) — these don't need to ship with the plugin.
386+
387+### Recommended companion: `garrytan/gstack`
388+
389+[`garrytan/gstack`](https://github.com/garrytan/gstack) is a Claude Code skill bundle (Garry Tan, MIT) that ships ~30 SDLC slash commands for AI-assisted engineering: `/office-hours` (product interrogation before coding), `/plan-eng-review` (architecture review), `/review` (code review for production bugs), `/qa` (test + regression-suite generation), `/ship` (sync + test + audit + push PR), `/cso` (OWASP Top 10 + STRIDE security audit), `/learn` (persistent project learnings), `/retro` (engineering retrospective), and others.
390+
391+**Install** (one-shot in any Claude Code session):
392+
52393 ```bash
53394 git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack \
54395 && cd ~/.claude/skills/gstack && ./setup
55396 ```
56397
57−See [CLAUDE.md § Recommended companion: garrytan/gstack](CLAUDE.md#recommended-companion-garrytangstack) for the per-command mapping. Optional but encouraged.
398+**How its commands map to open-forge work**:
58399
59−## Per-platform integration (when working on platform-specific bits)
400+| gstack command | When to use on open-forge |
401+|---|---|
402+| `/office-hours` | Before authoring a new module (backups, monitoring) or a bundle — interrogate the design before writing code. |
403+| `/plan-eng-review` | Before merging a major architectural addition (e.g. multi-platform support, agent-platform support) — catches the kind of cross-cutting issues that slipped past on PR #44 (in-bundle reference paths). |
404+| `/review` | On any PR that touches `references/projects/*.md`, `SKILL.md`, or `CLAUDE.md` — production-bug-flavored code review. |
405+| `/qa` | After authoring a new recipe — would force first-run-discipline-style verification before claiming Tier 1. |
406+| `/ship` | The PR-creation flow this session has been doing manually (sync main → regenerate dist → push → open PR with structured body). |
407+| `/cso` | Periodic security audit — credential handling module is the obvious target. |
408+| `/learn` | Capture session-level learnings (e.g. *"the bot polls newsletters — check origin/main before authoring duplicate work"*) into a persistent store the next AI session can read. |
409+| `/document-release` | Update README + CLAUDE.md + ARCHITECTURE.md to match shipped code — ran manually as PR #45 did. |
60410
61−If your patch touches platform-specific behavior, check the per-platform integration docs:
411+Optional but recommended for AI sessions and maintainers working on this repo. Not required — the catalog has been maintained without it. But the workflow patterns it encodes line up cleanly with how PR-authoring actually happens here.
62412
63−- [Claude Code](README.md#install) — canonical platform; auto-discovers via plugin marketplace
64−- [Codex](docs/platforms/codex.md) — system-prompt embedding or workspace files
65−- [Cursor](docs/platforms/cursor.md) — `.cursor/rules/` bundle
66−- [Aider](docs/platforms/aider.md) — `--read` flags + `CONVENTIONS.md`
67−- [Continue.dev](docs/platforms/continue.md) — context provider + slash command
68−- [OpenClaw](docs/platforms/openclaw.md) — workspace skill
69−- [Hermes-Agent](docs/platforms/hermes.md) — user skill
70−- [Generic agents](docs/platforms/generic.md) — any tools-using LLM
413+When a recipe is exercised end-to-end and a companion skill/MCP proved necessary — or a captured doc was added to `references/` — record it in the recipe's *Compatible runtimes* or a new *Companion tooling* note alongside upstream doc links. Same first-run discipline applies.
71414
72−Cross-platform behavior changes (e.g. credential handling) live in `references/modules/` so all platforms inherit them through the dist bundles.
415+## Recipe structure (must-have sections)
73416
74−## Reference
417+Every `references/projects/<software>.md` should have:
75418
76−For everything not covered above:
77−- **[BRD.md](BRD.md)** — *intent*: why the project exists, who it's for, success criteria, what we're explicitly not building.
78−- **[CLAUDE.md](CLAUDE.md)** — *policy*: what's in scope, strict-doc rules, sanitization, processing workflow.
79−- **[ARCHITECTURE.md](ARCHITECTURE.md)** — *system shape*: actors, data flow, state stores, quality gates, cadence.
419+| Section | Purpose |
420+|---|---|
421+| **Frontmatter** (name + description) | Loaded into context whenever the skill triggers. Keep concise; this is for Claude, not the user. |
422+| **Inputs to collect** (table keyed by phase) | Exact prompts, structured-choice options, defaults. So the same recipe is consistent across runs. |
423+| **Compatible runtimes** | Which runtime modules this software supports + recommended default |
424+| **Phase applicability** | Which of preflight/provision/dns/tls/smtp/inbound/hardening apply or skip |
425+| **Per-phase content** | Project-specific commands, config patches, verification checks |
426+| **Gotchas (consolidated)** | One-line summaries of every non-obvious thing learned in production. Single source of truth. |
427+| **TODO — verify on subsequent deployments** | Open questions to resolve on the next real deploy. Empty = recipe is fully validated. |
80428
81−User-facing project documentation lives in [README.md](README.md). End-user-skill content lives in [plugins/open-forge/skills/open-forge/SKILL.md](plugins/open-forge/skills/open-forge/SKILL.md).
429+`references/runtimes/<name>.md` and `references/infra/<name>.md` mirror this with their own scope (no `Inputs to collect` for infra usually — preflight handles AWS profile/region; infra adds bundle/region-specific bits).
430+
431+## First-run discipline
432+
433+When a recipe is exercised end-to-end against a real deployment for the first time:
434+
435+1. Capture every gotcha that surprised us into the recipe's *Gotchas* section.
436+2. Resolve / delete TODO items as they're answered.
437+3. Update the deployment state file's phase notes.
438+4. Bump `plugin.json` `version` (see *Versioning* below).
439+5. Commit.
440+
441+This is how the recipe stops being a guess and becomes a known-working deployment template. Don't skip it.
442+
443+The dominant path for first-run discipline is now **user-submitted feedback issues** processed per *Processing incoming issues* — the skill drafts a sanitized issue at the end of each deploy and the user opts in to share. Maintainer-driven deploys (where the maintainer is also the recipe author) still apply for new recipes. Either way, the same five-step capture applies.
444+
445+## File layout
446+
447+```
448+open-forge/
449+├── CLAUDE.md ← you are reading
450+├── AGENTS.md ← agents.md-standard landing page; thin pointer to CLAUDE.md
451+├── ARCHITECTURE.md ← system shape (actors, data flow, state stores, quality gates) — complement to this file
452+├── BRD.md ← project intent (why / who / success / non-goals) — strategic clarity
453+├── README.md ← user-facing, lives on GitHub
454+├── CHANGELOG.md ← user-visible changes per version (Keep-a-Changelog format; required on every version bump)
455+├── LICENSE ← MIT
456+├── .claude-plugin/marketplace.json ← marketplace manifest
457+├── .github/
458+│ ├── ISSUE_TEMPLATE/ ← three issue channels (recipe-feedback, software-nomination, method-proposal)
459+│ └── workflows/
460+│ ├── dist-bundles.yml ← CI: fail PRs whose dist/ bundles are stale vs canonical sources
461+│ └── release.yml ← auto-creates GitHub Release on plugin.json version bump
462+├── docs/platforms/ ← per-platform usage guides (Codex / Cursor / Aider / Continue / OpenClaw / Hermes / generic)
463+├── dist/ ← regenerated multi-platform distribution bundles (see scripts/build-dist.sh)
464+├── progress/ ← bot's state files: selfhst-progress.json + selfhst-software.json + issues-log.json (bot-owned) + sources.md (maintainer-curated source queue)
465+├── assets/ ← icon.svg + social-preview.svg
466+├── scripts/
467+│ └── build-dist.sh ← regenerates dist/ from canonical sources; run when CLAUDE.md / SKILL.md / modules change
468+└── plugins/open-forge/
469+ ├── .claude-plugin/plugin.json ← plugin manifest (version!)
470+ └── skills/open-forge/
471+ ├── SKILL.md ← end-user-Claude entrypoint
472+ ├── references/
473+ │ ├── projects/<name>.md ← software layer (2,200+ Tier 1 verified recipes)
474+ │ ├── runtimes/<name>.md ← runtime layer (docker.md, podman.md, native.md, kubernetes.md)
475+ │ ├── infra/<name>.md ← infra layer (aws/, azure/, hetzner/, digitalocean/, gcp/, oracle/, paas/, hostinger.md, raspberry-pi.md, macos-vm.md, byo-vps.md, localhost.md)
476+ │ ├── modules/<name>.md ← cross-cutting (preflight, dns, tls, smtp providers, inbound forwarders, tunnels, credentials, feedback, backups, monitoring)
477+ │ └── bundles/<name>.md ← curated multi-software bundles (recipe-of-recipes; ai-homelab, privacy-stack)
478+ └── scripts/ ← deployment-time operational scripts (per-recipe); empty by default
479+```
480+
481+The skill-side `plugins/open-forge/skills/open-forge/scripts/` (deployment-time) stays empty unless something is reused 3+ times across deployments — inline commands in recipes are clearer for one-off use. Distinct from the top-level `scripts/` (build-time tooling for dist/ bundles).
482+
483+For the **system architecture** (how the catalog grows, who maintains what, how an issue becomes a recipe edit, where state lives), see [`ARCHITECTURE.md`](ARCHITECTURE.md). This file is *policy*; ARCHITECTURE.md is *system shape*.
484+
485+## Versioning + publish flow
486+
487+`plugin.json` `version` controls what the Claude Code marketplace fetches.
488+
489+- **Bump on**: skill description change, new project/runtime/infra, major recipe rewrite, anything that changes user-visible behavior.
490+- **Don't bump on**: typo fixes, internal comment cleanups, lint-only changes.
491+
492+Publish flow (typical path: AI session processing an issue per *Issue-driven contribution model*):
493+
494+1. Add a `CHANGELOG.md` entry in user-visible terms (Keep-a-Changelog format) under `## [Unreleased]` → move to `## [<version>]` on bump.
495+2. Bump `plugin.json` `version`.
496+3. Commit and push to `main` (typically as a PR).
497+4. `.github/workflows/release.yml` auto-creates a GitHub Release tagged `v<version>` with notes pulled from the matching `CHANGELOG.md` section.
498+5. Users run `/plugin marketplace update` in their Claude Code session to pick up the new version.
499+
500+Maintainer manual edits follow the same flow but skip the issue-tracking labels.
501+
502+## Author convention
503+
504+Commits authored as `Qi Zhang <zhangqi444@gmail.com>` — set inline via env vars (`GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`, `GIT_COMMITTER_EMAIL`), **don't write to git config**.
505+
506+## Refactor (started 2026-04-24, completed 2026-04-26)
507+
508+Initial state collapsed three axes into linear "Path A/B/C" inside `openclaw.md`, which hid valid combos and biased preflight toward AWS even for non-AWS deployments. Migrated to the 3-layer file layout above. Order:
509+
510+1. ✅ CLAUDE.md model locked in (this section).
511+2. ✅ Preflight refactor — branch on infra choice; only require AWS CLI when infra ∈ AWS.
512+3. ✅ Skeleton infra adapters: `infra/aws/lightsail.md` (Bitnami + OpenClaw blueprints share this; the blueprint-vs-Ubuntu split is a project-recipe concern, not a separate adapter), `infra/aws/ec2.md`, `infra/azure/vm.md`, `infra/hetzner/cloud-cx.md`, `infra/digitalocean/droplet.md`, `infra/gcp/compute-engine.md`, `infra/oracle/free-tier-arm.md`, `infra/hostinger.md`, `infra/raspberry-pi.md`, `infra/macos-vm.md`, `infra/byo-vps.md`, `infra/localhost.md`, plus a PaaS family under `infra/paas/`: `fly.md`, `render.md`, `railway.md`, `northflank.md`, `exe-dev.md`.
513+4. ✅ Runtime modules: `runtimes/docker.md`, `runtimes/podman.md`, `runtimes/native.md`, `runtimes/kubernetes.md`. Docker + native extracted from openclaw.md Paths B and C; kubernetes added when openclaw upstream's Kustomize-based path was wired in; podman added in v0.8.0.
514+5. ✅ Slim down `projects/openclaw.md` — software-layer concerns only; reference runtimes + infra modules for everything else. v0.8.0: corrected the Kubernetes section to be Kustomize-first (matches upstream `scripts/k8s/deploy.sh`); added Podman, ClawDock, Ansible, Nix, and Bun (experimental) sections; combo table now enumerates every upstream-blessed install method documented under `docs.openclaw.ai/install/*`.
515+6. ✅ Add `modules/tunnels.md` for localhost public-reach (Cloudflare Tunnel / Tailscale / ngrok).
516+7. ✅ Update SKILL.md, README.md support tables and prompts. Bump plugin version (→ 0.8.0).
517+
518+Path A/B/C terminology retired. Future work tracked in each adapter's *TODO — verify on subsequent deployments* section, not here. Cluster-provisioning adapters (EKS / GKE / AKS / DOKS) are intentionally not in scope — open-forge orchestrates an existing cluster; users own cluster create/delete in their cloud's k8s UI. Cloud-VM adapters and PaaS adapters added in v0.8.0 are documented from upstream docs only — none has been exercised end-to-end yet; first-run discipline (CLAUDE.md § *First-run discipline*) applies as those deployments happen.
519+
520+## Behavioral guidelines (echoes of bota CLAUDE.md, kept here for autonomy)
521+
522+- **Think before coding.** State assumptions; ask when uncertain; surface tradeoffs.
523+- **Simplicity first.** Minimum recipe content that works; no speculative abstractions.
524+- **Surgical changes.** When updating a recipe after a deploy, change only what the deploy taught us. Don't "improve" adjacent sections.
525+- **Goal-driven execution.** A recipe edit is "done" when the next deploy can use it without manual fixes.
526+- **Documentation updates** (the recipes themselves) are a deliverable of every deployment, not a follow-up.
82527
