From 0453cde135ae0c0b51eece93ed549c73758ee6a5 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 15:31:25 +0000 Subject: [PATCH 1/5] Fix validator runtime, add rule registry, drop stub rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The validator failed at import time because no-dialog-apis.ts imported a non-existent helper (lineFromOffset, ctx.lineStarts) and several other rule files were stubs that imported the same missing symbol. Rewrite the broken rule against the existing parser API, delete the five unimplemented stubs (aria-landmarks, contrast-minimum, no-empty-elements, no-inline-styles-except-root, responsive-images) so they can't silently regress the test run, and implement three concrete rules that the user-facing docs promised: lang-attribute (error, Rule 13), focus-visible (warning, Rule 14), and print-media-query (warning, Rule 7). Introduce src/rule-registry.ts as the single source of truth for which rules are active. The CLI entry imports ALL_RULES from there, so README claims and runtime behavior can no longer drift. Extend the test suite (10 → 12 tests) with negative fixtures for the new rules, and update valid.html so it satisfies the now-stricter rule set (adds :focus-visible and @media print blocks). The dialog-apis fixture is rewritten to put alert/prompt/confirm calls in a script block so the test asserts the rule fires on exactly three call sites, not on the inline handlers that an unrelated rule would also catch. bloom-validator/README.md is rewritten to list the 10 active rules, the security-hardening sub-rules, and a "Planned (not yet enforced)" list so removed stubs are tracked as roadmap items rather than disappearing silently. --- bloom-validator/README.md | 50 ++++++++++------ bloom-validator/src/index.ts | 20 +------ bloom-validator/src/rule-registry.ts | 24 ++++++++ bloom-validator/src/rules/aria-landmarks.ts | 11 ---- bloom-validator/src/rules/contrast-minimum.ts | 11 ---- bloom-validator/src/rules/focus-visible.ts | 58 +++++++++++++++++-- bloom-validator/src/rules/lang-attribute.ts | 54 +++++++++++++++-- bloom-validator/src/rules/no-dialog-apis.ts | 50 ++++++---------- .../src/rules/no-empty-elements.ts | 11 ---- .../src/rules/no-inline-styles-except-root.ts | 11 ---- .../src/rules/print-media-query.ts | 25 ++++++-- .../src/rules/responsive-images.ts | 11 ---- .../tests/fixtures/invalid-dialog-apis.html | 33 ++++++++--- .../tests/fixtures/invalid-lang.html | 22 +++++++ .../tests/fixtures/invalid-print-focus.html | 21 +++++++ bloom-validator/tests/fixtures/valid.html | 5 ++ bloom-validator/tests/validator.test.ts | 24 ++++++++ .../{ => skeletons}/accessibility-report.html | 0 .../{ => skeletons}/api-documentation.html | 0 .../architecture-decision.html | 0 .../{ => skeletons}/dependency-audit.html | 0 templates/{ => skeletons}/design-review.html | 0 templates/{ => skeletons}/migration-plan.html | 0 templates/{ => skeletons}/monthly-review.html | 0 .../{ => skeletons}/onboarding-guide.html | 0 templates/{ => skeletons}/sprint-retro.html | 0 templates/{ => skeletons}/weekly-digest.html | 0 27 files changed, 298 insertions(+), 143 deletions(-) create mode 100644 bloom-validator/src/rule-registry.ts delete mode 100644 bloom-validator/src/rules/aria-landmarks.ts delete mode 100644 bloom-validator/src/rules/contrast-minimum.ts delete mode 100644 bloom-validator/src/rules/no-empty-elements.ts delete mode 100644 bloom-validator/src/rules/no-inline-styles-except-root.ts delete mode 100644 bloom-validator/src/rules/responsive-images.ts create mode 100644 bloom-validator/tests/fixtures/invalid-lang.html create mode 100644 bloom-validator/tests/fixtures/invalid-print-focus.html rename templates/{ => skeletons}/accessibility-report.html (100%) rename templates/{ => skeletons}/api-documentation.html (100%) rename templates/{ => skeletons}/architecture-decision.html (100%) rename templates/{ => skeletons}/dependency-audit.html (100%) rename templates/{ => skeletons}/design-review.html (100%) rename templates/{ => skeletons}/migration-plan.html (100%) rename templates/{ => skeletons}/monthly-review.html (100%) rename templates/{ => skeletons}/onboarding-guide.html (100%) rename templates/{ => skeletons}/sprint-retro.html (100%) rename templates/{ => skeletons}/weekly-digest.html (100%) diff --git a/bloom-validator/README.md b/bloom-validator/README.md index 2dd6b02..9f2086e 100644 --- a/bloom-validator/README.md +++ b/bloom-validator/README.md @@ -1,11 +1,9 @@ # bloom-validator -A zero-dependency TypeScript CLI that validates `.html` files against Bloom's 12 construction rules and 8 security rules. +A zero-dependency TypeScript CLI that validates `.html` files against Bloom's construction and security rules. Runs on Node ≥ 22.6 using native TypeScript type-stripping — no build step, no dependencies. ## Quick start -Requires Node ≥ 22.6 (uses native TypeScript type-stripping — no build step). - ```bash node src/index.ts path/to/file.html node src/index.ts path/to/file.html --json @@ -20,19 +18,41 @@ Exit codes: ## Rules implemented +The validator currently enforces 10 rules. Each rule is a single file under [`src/rules/`](src/rules/) and is registered in [`src/rule-registry.ts`](src/rule-registry.ts). + | ID | Name | Severity | Description | |---|---|---|---| -| `rule-1` | `no-external-deps` | error | No ` diff --git a/bloom-validator/tests/fixtures/invalid-lang.html b/bloom-validator/tests/fixtures/invalid-lang.html new file mode 100644 index 0000000..f2c6c7e --- /dev/null +++ b/bloom-validator/tests/fixtures/invalid-lang.html @@ -0,0 +1,22 @@ + + + + + +Broken — Missing lang + + + +

No lang attribute

+
+
+

This document is missing a lang on the html element.

+
+
+ + diff --git a/bloom-validator/tests/fixtures/invalid-print-focus.html b/bloom-validator/tests/fixtures/invalid-print-focus.html new file mode 100644 index 0000000..edf510a --- /dev/null +++ b/bloom-validator/tests/fixtures/invalid-print-focus.html @@ -0,0 +1,21 @@ + + + + + +Warns — no print, no focus + + + +

Missing print styles and focus styles

+
+
+ +
+
+ + diff --git a/bloom-validator/tests/fixtures/valid.html b/bloom-validator/tests/fixtures/valid.html index 1f34094..8cf633e 100644 --- a/bloom-validator/tests/fixtures/valid.html +++ b/bloom-validator/tests/fixtures/valid.html @@ -21,6 +21,11 @@ } .page { max-width: 860px; margin: 0 auto; } .card { border: 1.5px solid var(--gray-300); padding: 20px; } +.card:focus-visible { outline: 2px solid var(--clay); outline-offset: 2px; } +@media print { + body { background: var(--ivory); padding: 0; } + .card { break-inside: avoid; } +} diff --git a/bloom-validator/tests/validator.test.ts b/bloom-validator/tests/validator.test.ts index 76270a8..ae35b13 100644 --- a/bloom-validator/tests/validator.test.ts +++ b/bloom-validator/tests/validator.test.ts @@ -150,4 +150,28 @@ describe("bloom-validator", () => { { passed: true, errorCount: 0 }, ); }); + + it("flags missing lang attribute on (Rule 13)", () => { + const { path, source } = load("invalid-lang.html"); + const report = validate(path, source); + assert.equal(report.passed, false); + const langIssues = report.issues.filter((i) => i.ruleName === "lang-attribute"); + assert.equal(langIssues.length, 1, `expected 1 lang issue, got ${langIssues.length}`); + assert.match(langIssues[0]!.message, /missing a lang attribute/); + }); + + it("warns when no @media print and no :focus styles (Rules 7, 14)", () => { + const { path, source } = load("invalid-print-focus.html"); + const report = validate(path, source); + // Both rules emit warnings, not errors, so passed should still be true. + assert.equal(report.errorCount, 0, `expected 0 errors, got ${report.errorCount}`); + const printIssues = report.issues.filter((i) => i.ruleName === "print-media-query"); + const focusIssues = report.issues.filter((i) => i.ruleName === "focus-visible"); + assert.equal(printIssues.length, 1, "expected exactly 1 print-media-query warning"); + assert.equal(printIssues[0]!.severity, "warning"); + assert.ok(focusIssues.length >= 1, "expected at least 1 focus-visible warning"); + for (const issue of focusIssues) { + assert.equal(issue.severity, "warning"); + } + }); }); diff --git a/templates/accessibility-report.html b/templates/skeletons/accessibility-report.html similarity index 100% rename from templates/accessibility-report.html rename to templates/skeletons/accessibility-report.html diff --git a/templates/api-documentation.html b/templates/skeletons/api-documentation.html similarity index 100% rename from templates/api-documentation.html rename to templates/skeletons/api-documentation.html diff --git a/templates/architecture-decision.html b/templates/skeletons/architecture-decision.html similarity index 100% rename from templates/architecture-decision.html rename to templates/skeletons/architecture-decision.html diff --git a/templates/dependency-audit.html b/templates/skeletons/dependency-audit.html similarity index 100% rename from templates/dependency-audit.html rename to templates/skeletons/dependency-audit.html diff --git a/templates/design-review.html b/templates/skeletons/design-review.html similarity index 100% rename from templates/design-review.html rename to templates/skeletons/design-review.html diff --git a/templates/migration-plan.html b/templates/skeletons/migration-plan.html similarity index 100% rename from templates/migration-plan.html rename to templates/skeletons/migration-plan.html diff --git a/templates/monthly-review.html b/templates/skeletons/monthly-review.html similarity index 100% rename from templates/monthly-review.html rename to templates/skeletons/monthly-review.html diff --git a/templates/onboarding-guide.html b/templates/skeletons/onboarding-guide.html similarity index 100% rename from templates/onboarding-guide.html rename to templates/skeletons/onboarding-guide.html diff --git a/templates/sprint-retro.html b/templates/skeletons/sprint-retro.html similarity index 100% rename from templates/sprint-retro.html rename to templates/skeletons/sprint-retro.html diff --git a/templates/weekly-digest.html b/templates/skeletons/weekly-digest.html similarity index 100% rename from templates/weekly-digest.html rename to templates/skeletons/weekly-digest.html From 738725ffaf2c8dbd96858b33fcaa0f999bf2522a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 15:31:51 +0000 Subject: [PATCH 2/5] Clean every template against the validator, add worked examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rich templates (annotated-pr-review, exploration-code-approaches, incident-timeline, status-report) shipped with stray hex literals outside :root, no
landmark, and no focus/print styles — every one failed bloom-validator. Promote each stray color into a :root token (--sand, --sand-deep, --diff-del, --diff-add, --code-fg, --code-fg-muted), wrap their body content in
, and add :focus-visible + @media print blocks so each artifact prints cleanly and announces focus state. The ten thin 20-line templates (accessibility-report, api-documentation, architecture-decision, dependency-audit, design-review, migration-plan, monthly-review, onboarding-guide, sprint-retro, weekly-digest) were indistinguishable from each other and contained literal "Generated: placeholder date" / "Template for X content" copy. Rewrite each as a clearly-labeled skeleton with a leading skeleton-purpose comment, data-template="" markers in place of placeholder strings, and a print media query so a user can tell at a glance that they are starter scaffolds, not production examples. Add examples/ with three fully worked artifacts that the README has been claiming exist: - pr-review-example.html — annotated PR review with real-shaped Go diffs, risk chips, file cards, comment bubbles, and a next-steps checklist - incident-report-example.html — INC-2026-0143 SEV-2 postmortem with timeline, root cause diff, impact table, and action items - design-system-example.html — living design-system reference with copyable color tokens, the full type scale, and a composed preview All 5 production templates, 10 skeletons, and 3 examples pass bloom-validator with zero issues. --- examples/design-system-example.html | 296 ++++++++++++++++++ examples/incident-report-example.html | 140 +++++++++ examples/pr-review-example.html | 230 ++++++++++++++ templates/annotated-pr-review.html | 36 ++- templates/exploration-code-approaches.html | 15 +- templates/incident-timeline.html | 11 +- templates/skeletons/accessibility-report.html | 53 +++- templates/skeletons/api-documentation.html | 53 +++- .../skeletons/architecture-decision.html | 53 +++- templates/skeletons/dependency-audit.html | 53 +++- templates/skeletons/design-review.html | 53 +++- templates/skeletons/migration-plan.html | 53 +++- templates/skeletons/monthly-review.html | 53 +++- templates/skeletons/onboarding-guide.html | 53 +++- templates/skeletons/sprint-retro.html | 53 +++- templates/skeletons/weekly-digest.html | 53 +++- templates/status-report.html | 13 +- 17 files changed, 1166 insertions(+), 105 deletions(-) create mode 100644 examples/design-system-example.html create mode 100644 examples/incident-report-example.html create mode 100644 examples/pr-review-example.html diff --git a/examples/design-system-example.html b/examples/design-system-example.html new file mode 100644 index 0000000..c11ff55 --- /dev/null +++ b/examples/design-system-example.html @@ -0,0 +1,296 @@ + + + + + +Bloom Design System — Living Reference + + + +
+
+
Bloom · Living design system
+

Tokens, type, and components — all in one file

+

This is what a Bloom design-system reference looks like as an artifact: copy-able tokens, the full type scale, and the small set of components every Bloom-produced page composes from. No build step, no external dependencies, prints cleanly.

+
+
+ +
+

Colors

+

Tap a swatch's copy button to copy the var(--token) reference to your clipboard.

+
+
Ivory
var(--ivory)#FAF9F5
+
Slate
var(--slate)#141413
+
Clay
var(--clay)#D97757
+
Oat
var(--oat)#E3DACC
+
Olive
var(--olive)#788C5D
+
Rust
var(--rust)#B04A3F
+
Gray 100
var(--gray-100)#F0EEE6
+
Gray 300
var(--gray-300)#D1CFC5
+
Gray 500
var(--gray-500)#87867F
+
Gray 700
var(--gray-700)#3D3D3A
+
+
+ +
+

Typography

+

Two families — serif (--serif) for headings, sans (--sans) for body, mono (--mono) for code, tokens, and metadata.

+
Display
44 / 1.1
The Unreasonable Effectiveness of HTML
+
H1
30 / 1.25
Sprint 44 — Acme
+
H2
22 / 1.3
Highlights from the last two weeks
+
Body
15 / 1.6
The skill captures the patterns from "The Unreasonable Effectiveness of HTML" and makes them reproducible across every agent harness.
+
Mono
13 / 1.4
var(--clay) /* #D97757 */
+
+ +
+

Components

+

Buttons, pills, inputs — the small palette every Bloom artifact draws from.

+
+
+

Buttons

+ + + +
+
+

Pills

+ Shipped + Blocking + In review + Triaged +
+
+

Input

+ + +
+
+
+ +
+

Composed preview

+

A miniature page using the tokens above.

+
+
Sprint 44 · highlight card
+

Shipped the onboarding empty-state rewrite

+

Mira Okafor led the redesign; rollout reached 100% of tenants on Tuesday. Median time-to-first-action dropped from 4m 12s to 1m 38s.

+ +
+
+
+
+ + + diff --git a/examples/incident-report-example.html b/examples/incident-report-example.html new file mode 100644 index 0000000..d225df8 --- /dev/null +++ b/examples/incident-report-example.html @@ -0,0 +1,140 @@ + + + + + +acme — INC-2026-0143 OAuth webhook timeouts + + + +
+
+
INC-2026-0143
+

OAuth webhook timeouts on token rotation

+
+ SEV-2 + Resolved + Duration 47m + Detected 2026-05-12 14:08 UTC + Owner @platform-oncall +
+
+
+ +
+
TL;DR
+

A token-rotation deploy at 14:02 UTC raised webhook handler latency from p99 ~250ms to ~12s, causing 3% of OAuth callbacks to fail for 47 minutes. The new refreshToken() path made a synchronous round-trip to the identity service per request instead of using the cached token. Resolved by rolling back the deploy and shipping a fix with a 5-minute cache TTL.

+
+ +
+

Timeline

+
+
+
14:02 UTC
Deploy v2.41.0 rolls out to production. Token rotation refactor is included.
+
14:08 UTC
Impact starts. PagerDuty fires on webhook_latency_p99 > 5s. OAuth callbacks begin timing out for tenants whose tokens rotated in the last 24h.
+
14:14 UTC
@mira-okafor takes incident command. Status page updated to "Investigating".
+
14:23 UTC
Identity-service dashboard shows a 40× spike in GetToken RPC volume from the API tier.
+
14:31 UTC
Mitigated. Rolled back to v2.40.3. Latency returns to baseline within 90s.
+
14:55 UTC
Status page updated to "Resolved". 3.1% of OAuth callbacks failed during the window; affected tenants notified.
+
+
+ +
+

Root cause

+
+

The token-rotation refactor removed the in-process token cache in favor of a "single source of truth" pattern, but the replacement code path made a synchronous gRPC call to the identity service on every webhook callback — adding ~50ms of latency per request and saturating the identity service at peak traffic.

+
+ internal/oauth/token_store.go +
func (s *TokenStore) Get(tenant string) (*Token, error) {
+
- if cached, ok := s.cache.Get(tenant); ok { return cached, nil }
+
+ // Always fetch fresh — single source of truth
+
return s.client.GetToken(ctx, tenant)
+
}
+
+
+ +
+

Impact

+
+ + + + + + +
Duration of impact47m (14:08 → 14:55 UTC)
Failed OAuth callbacks3,112 (3.1%)
Tenants affected184 of 6,420
Customer-reported tickets9
Revenue at risk~$2,300 (refund-eligible)
+
+ +
+

Action items

+
+
+
MORoll back v2.41.0 and re-ship token-rotation with a 5-minute cache TTL2026-05-12
+
JKNotify affected tenants and process refund-eligible accounts2026-05-13
+
PTAdd load test that catches identity-service RPC spikes in CI before deploy2026-05-22
+
MODocument the cache-first invariant in docs/oauth/architecture.md2026-05-27
+
SDSet identity_service_rps SLO alert at 80% of measured capacity2026-06-03
+
+
+
+
+ + diff --git a/examples/pr-review-example.html b/examples/pr-review-example.html new file mode 100644 index 0000000..67f512c --- /dev/null +++ b/examples/pr-review-example.html @@ -0,0 +1,230 @@ + + + + + +acme/api — Cache OAuth tokens per tenant Review + + + +
+
+
acme/api · Pull Request #4421
+

Cache OAuth tokens per tenant

+
+
MO
+
Mira Okaforopened 2 days ago
+
mira/oauth-token-cache main
+
+184 / −47 4 files changed
+
+
+
+ +
+

Risk map

+ +
+ safe — tests or trivial change + worth a look — verify edge cases + needs attention — could regress prod +
+
+ +
+

Files

+ +
+
+
internal/oauth/token_store.go
+
+ Needs attention +
+
+
+
112 func (s *TokenStore) Get(ctx context.Context, tenantID string) (*Token, error) {
+
113- raw, err := s.db.QueryRow(ctx, "SELECT token FROM tokens WHERE tenant=$1", tenantID).Scan(&raw)
+
113+ if cached, ok := s.cache.Get(tenantID); ok {
+
114+ return cached.(*Token), nil
+
115+ }
+
116+ raw, err := s.db.QueryRow(ctx, getTokenQuery, tenantID).Scan(&raw)
+
117 if err != nil {
+
118 return nil, fmt.Errorf("token lookup: %w", err)
+
+
+
+
L113–L116
+

Blocking The cache is populated only on miss — on token rotation the stale value will be served until TTL expires. Either invalidate on Rotate() or use a write-through pattern.

+
+
+
L116
+

Nit Pulling the query into a package-level const (getTokenQuery) is nice — also pull the table name into a constant to match the rest of the file.

+
+
+
+ +
+
+
internal/cache/redis_client.go
+
+ Worth a look +
+
+
+
38+func (c *RedisClient) GetWithTTL(key string) (interface{}, bool) {
+
39+ val, err := c.conn.Get(c.ctx, key).Result()
+
40+ if err == redis.Nil { return nil, false }
+
41+ return val, err == nil
+
42+}
+
+
+
+
L40
+

Question Swallowing non-redis.Nil errors here hides connection drops from callers. Worth logging at warn or returning the error?

+
+
+
+ +
+
+
api/handlers/token.go
+
+ Safe +
+
+
+
22 func (h *Handler) Token(w http.ResponseWriter, r *http.Request) {
+
23- tok, err := h.store.GetUncached(r.Context(), tenant)
+
23+ tok, err := h.store.Get(r.Context(), tenant)
+
+
+
+
L23
+

LGTM Drop-in replacement, same signature.

+
+
+
+ +
+
+
internal/oauth/token_store_test.go
+
+ Safe +
+
+
+
+62+ t.Run("cache hit avoids db round-trip", func(t *testing.T) { ... })
+
+78+ t.Run("cache invalidates on rotate", func(t *testing.T) { ... })
+
+
+
+
L78
+

Note Second test stub is currently TODO — fill in before merge.

+
+
+
+
+ +
+

Suggested next steps

+
    +
  • +
  • +
  • +
  • +
+
+
+
+ + diff --git a/templates/annotated-pr-review.html b/templates/annotated-pr-review.html index 725b401..b9521a8 100644 --- a/templates/annotated-pr-review.html +++ b/templates/annotated-pr-review.html @@ -9,13 +9,15 @@ --ivory: #FAF9F5; --slate: #141413; --clay: #D97757; --oat: #E3DACC; --olive: #788C5D; --rust: #B04A3F; --gray-100: #F0EEE6; --gray-300: #D1CFC5; --gray-500: #87867F; --gray-700: #3D3D3A; --white: #FFFFFF; + --sand: #B89B6E; --sand-deep: #7A6A4F; + --code-fg: #E8E6DC; --code-fg-muted: #B8B6AC; --serif: ui-serif, Georgia, serif; --sans: system-ui, -apple-system, sans-serif; --mono: ui-monospace, "SF Mono", Menlo, monospace; } * { box-sizing: border-box; margin: 0; padding: 0; } body { background: var(--ivory); color: var(--gray-700); font-family: var(--sans); font-size: 15px; line-height: 1.6; padding: 48px 24px 80px; } .page { max-width: 920px; margin: 0 auto; } -header.pr-head { border: 1.5px solid var(--gray-300); border-radius: 12px; padding: 28px 32px; background: #fff; margin-bottom: 36px; } +header.pr-head { border: 1.5px solid var(--gray-300); border-radius: 12px; padding: 28px 32px; background: var(--white); margin-bottom: 36px; } .repo-line { font-family: var(--mono); font-size: 12.5px; color: var(--gray-500); margin-bottom: 10px; } h1 { font-family: var(--serif); font-weight: 500; font-size: 30px; color: var(--slate); margin-bottom: 18px; line-height: 1.25; } .meta-row { display: flex; align-items: center; flex-wrap: wrap; gap: 20px; } @@ -28,37 +30,37 @@ section { margin-bottom: 40px; } h2 { font-family: var(--serif); font-weight: 500; font-size: 21px; color: var(--slate); margin-bottom: 14px; } .risk-map { display: flex; flex-wrap: wrap; gap: 10px; } -.chip { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; border-radius: 8px; border: 1.5px solid var(--gray-300); font-family: var(--mono); font-size: 12.5px; color: var(--slate); text-decoration: none; background: #fff; transition: transform 0.12s ease; } +.chip { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; border-radius: 8px; border: 1.5px solid var(--gray-300); font-family: var(--mono); font-size: 12.5px; color: var(--slate); text-decoration: none; background: var(--white); transition: transform 0.12s ease; } .chip:hover { transform: translateY(-1px); } .chip .dot { width: 9px; height: 9px; border-radius: 50%; } .chip.safe { background: rgba(120,140,93,0.10); border-color: rgba(120,140,93,0.45); } .chip.safe .dot { background: var(--olive); } .chip.medium { background: var(--oat); } -.chip.medium .dot { background: #B89B6E; } +.chip.medium .dot { background: var(--sand); } .chip.attention { background: rgba(217,119,87,0.12); border-color: rgba(217,119,87,0.55); } .chip.attention .dot { background: var(--clay); } .legend { margin-top: 12px; font-size: 12px; color: var(--gray-500); display: flex; gap: 18px; } .legend span { display: inline-flex; align-items: center; gap: 6px; } .legend .dot { width: 8px; height: 8px; border-radius: 50%; } -.file-card { border: 1.5px solid var(--gray-300); border-radius: 12px; background: #fff; margin-bottom: 24px; overflow: hidden; scroll-margin-top: 20px; } +.file-card { border: 1.5px solid var(--gray-300); border-radius: 12px; background: var(--white); margin-bottom: 24px; overflow: hidden; scroll-margin-top: 20px; } .file-head { padding: 16px 20px; border-bottom: 1.5px solid var(--gray-100); display: flex; align-items: center; justify-content: space-between; gap: 12px; } .file-path { font-family: var(--mono); font-size: 13.5px; color: var(--slate); } .risk-tag { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; padding: 3px 8px; border-radius: 6px; font-weight: 600; } .risk-tag.safe { background: rgba(120,140,93,0.15); color: var(--olive); } -.risk-tag.medium { background: var(--oat); color: #7A6A4F; } +.risk-tag.medium { background: var(--oat); color: var(--sand-deep); } .risk-tag.attention { background: rgba(217,119,87,0.15); color: var(--clay); } .diff { background: var(--slate); font-family: var(--mono); font-size: 12.5px; line-height: 1.7; overflow-x: auto; } .diff-row { display: grid; grid-template-columns: 48px 18px 1fr; padding: 0 14px 0 0; white-space: pre; } .diff-row .ln { text-align: right; padding-right: 14px; color: var(--gray-500); user-select: none; } .diff-row .mark { text-align: center; color: var(--gray-500); } -.diff-row .code { color: #E8E6DC; } -.diff-row.ctx .code { color: #B8B6AC; } +.diff-row .code { color: var(--code-fg); } +.diff-row.ctx .code { color: var(--code-fg-muted); } .diff-row.add { background: rgba(120,140,93,0.15); } .diff-row.add .mark { color: var(--olive); } .diff-row.del { background: rgba(176,74,63,0.15); } .diff-row.del .mark { color: var(--rust); } .comments { padding: 18px 20px 20px; background: var(--gray-100); display: flex; flex-direction: column; gap: 14px; } -.bubble { position: relative; background: #fff; border: 1.5px solid var(--gray-300); border-left-width: 4px; border-radius: 8px; padding: 12px 14px 12px 16px; max-width: 680px; } +.bubble { position: relative; background: var(--white); border: 1.5px solid var(--gray-300); border-left-width: 4px; border-radius: 8px; padding: 12px 14px 12px 16px; max-width: 680px; } .bubble.blocking { border-left-color: var(--clay); } .bubble.nit { border-left-color: var(--gray-300); } .bubble .anchor { font-family: var(--mono); font-size: 11.5px; color: var(--gray-500); margin-bottom: 4px; } @@ -67,19 +69,29 @@ .bubble.nit .label { color: var(--gray-500); } .bubble p { font-size: 13.5px; color: var(--gray-700); } .bubble code { font-family: var(--mono); font-size: 12.5px; background: var(--gray-100); padding: 1px 5px; border-radius: 4px; } -details.file-collapsed { border: 1.5px solid var(--gray-300); border-radius: 12px; background: #fff; margin-bottom: 14px; } +details.file-collapsed { border: 1.5px solid var(--gray-300); border-radius: 12px; background: var(--white); margin-bottom: 14px; } details.file-collapsed summary { list-style: none; cursor: pointer; padding: 14px 20px; display: flex; align-items: center; justify-content: space-between; gap: 12px; } details.file-collapsed summary::-webkit-details-marker { display: none; } details.file-collapsed summary::after { content: "+"; font-family: var(--mono); color: var(--gray-500); font-size: 16px; } details.file-collapsed[open] summary::after { content: "−"; } details.file-collapsed .body { padding: 0 20px 16px; font-size: 13.5px; color: var(--gray-700); } -footer.next-steps { border: 1.5px solid var(--gray-300); border-radius: 12px; background: #fff; padding: 24px 28px; } +footer.next-steps { border: 1.5px solid var(--gray-300); border-radius: 12px; background: var(--white); padding: 24px 28px; } footer h2 { font-family: var(--serif); font-weight: 500; font-size: 22px; color: var(--slate); margin-bottom: 16px; } .checklist { list-style: none; padding: 0; } .checklist li { display: flex; align-items: flex-start; gap: 12px; padding: 8px 0; } .checklist input[type="checkbox"] { width: 17px; height: 17px; margin-top: 2px; accent-color: var(--olive); cursor: pointer; } .checklist label { cursor: pointer; flex: 1; } .checklist code { font-family: var(--mono); font-size: 12.5px; background: var(--gray-100); padding: 1px 5px; border-radius: 4px; } +a:focus-visible, button:focus-visible, summary:focus-visible, input:focus-visible { + outline: 2px solid var(--clay); outline-offset: 2px; border-radius: 4px; +} +@media print { + body { background: var(--ivory); color: var(--slate); padding: 24px; } + .file-card, .bubble, footer.next-steps, header.pr-head { break-inside: avoid; } + .diff { background: var(--gray-100); } + .diff-row .code { color: var(--slate); } + .diff-row.ctx .code { color: var(--gray-700); } +} @@ -94,6 +106,7 @@

[PR TITLE]

+[NUM] / −[NUM] [NUM] files changed
+

Risk map

@@ -102,7 +115,7 @@

Risk map

safe - worth a look + worth a look needs attention
@@ -133,6 +146,7 @@

Suggested next steps

  • +
    diff --git a/templates/exploration-code-approaches.html b/templates/exploration-code-approaches.html index 2ecbdd8..afc2020 100644 --- a/templates/exploration-code-approaches.html +++ b/templates/exploration-code-approaches.html @@ -16,6 +16,7 @@ --gray-500: #87867F; --gray-700: #3D3D3A; --white: #FFFFFF; + --code-fg: #E8E6DE; --serif: ui-serif, Georgia, "Times New Roman", serif; --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; --mono: ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace; @@ -107,7 +108,7 @@ font-family: var(--mono); font-size: 12.5px; line-height: 1.65; - color: #E8E6DE; + color: var(--code-fg); white-space: pre; } .tradeoffs { @@ -174,6 +175,16 @@ @media (max-width: 1100px) { .approaches { grid-template-columns: 1fr; } } +a:focus-visible, button:focus-visible, .approach:focus-visible { + outline: 2px solid var(--clay); outline-offset: 2px; border-radius: 4px; +} +@media print { + body { background: var(--ivory); color: var(--slate); padding: 24px; } + .approaches { grid-template-columns: 1fr; } + .approach { break-inside: avoid; } + .code { background: var(--gray-100); } + .code pre { color: var(--slate); } +} @@ -186,6 +197,7 @@

    [TITLE]

    [PROMPT TEXT] +
    @@ -210,6 +222,7 @@

    01[APPROACH NAME]

    Recommendation

    [RECOMMENDATION WITH RATIONALE]

    +
    diff --git a/templates/incident-timeline.html b/templates/incident-timeline.html index 1e841aa..54dcec6 100644 --- a/templates/incident-timeline.html +++ b/templates/incident-timeline.html @@ -8,6 +8,7 @@ :root { --ivory:#FAF9F5;--slate:#141413;--clay:#D97757;--oat:#E3DACC;--olive:#788C5D; --gray-100:#F0EEE6;--gray-300:#D1CFC5;--gray-500:#87867F;--gray-700:#3D3D3A;--white:#FFFFFF; + --diff-del:#E0897A;--diff-add:#A3B88A; --serif:ui-serif,Georgia,serif;--sans:system-ui,-apple-system,sans-serif; --mono:ui-monospace,"SF Mono",Menlo,monospace; } @@ -38,7 +39,7 @@ .tl-body{font-size:14px;color:var(--gray-700)}.tl-body strong{color:var(--slate);font-weight:600} .code-panel{background:var(--slate);color:var(--gray-100);border-radius:12px;padding:18px 20px;font-family:var(--mono);font-size:13px;line-height:1.7;overflow-x:auto;margin:8px 0 4px} .code-panel .path{color:var(--gray-500);font-size:12px;margin-bottom:10px;display:block} -.diff-line{white-space:pre}.diff-line.ctx{color:var(--gray-300)}.diff-line.del{color:#E0897A}.diff-line.add{color:#A3B88A} +.diff-line{white-space:pre}.diff-line.ctx{color:var(--gray-300)}.diff-line.del{color:var(--diff-del)}.diff-line.add{color:var(--diff-add)} table.impact{width:100%;max-width:460px;border-collapse:separate;border-spacing:0;background:var(--white);border:1.5px solid var(--gray-300);border-radius:12px;overflow:hidden} table.impact th,table.impact td{text-align:left;padding:12px 18px;font-size:14px;border-bottom:1px solid var(--gray-100)} table.impact tr:last-child th,table.impact tr:last-child td{border-bottom:none} @@ -53,6 +54,12 @@ .ai-row.done .ai-desc{color:var(--gray-500);text-decoration:line-through;text-decoration-color:var(--gray-300)} .ai-avatar{width:30px;height:30px;border-radius:50%;background:var(--oat);color:var(--gray-700);font-size:11px;font-weight:600;display:flex;align-items:center;justify-content:center;letter-spacing:0.02em} .ai-desc{font-size:14px;color:var(--slate)}.ai-due{font-family:var(--mono);font-size:12px;color:var(--gray-500);text-align:right} +a:focus-visible,button:focus-visible,details summary:focus-visible{outline:2px solid var(--clay);outline-offset:2px;border-radius:4px} +@media print{ + body{background:var(--ivory);color:var(--slate);padding:24px} + .pill{border:1px solid var(--gray-300)} + section,.tl-entry{break-inside:avoid} +} @@ -68,6 +75,7 @@

    [INCIDENT TITLE]

    Owner [NAME] +
    TL;DR
    @@ -113,6 +121,7 @@

    Action items

    [INIT][ACTION][DATE]
    +
    diff --git a/templates/skeletons/accessibility-report.html b/templates/skeletons/accessibility-report.html index 269832a..beca394 100644 --- a/templates/skeletons/accessibility-report.html +++ b/templates/skeletons/accessibility-report.html @@ -1,21 +1,56 @@ - + + - + -Accessibility Report +Accessibility Report — Bloom skeleton -

    Accessibility Report

    Generated: placeholder date

    +
    +

    Accessibility Report

    +

    Replace with a real date — e.g. May 19, 2026

    +
    -

    Overview

    Template for accessibility report content.

    +

    Skeleton template. Replace each data-template slot with project-specific content before publishing. See ../../docs/construction-rules.md for the rules every Bloom artifact must satisfy.

    +
    +

    Overview

    +

    Replace this starter summary with a one-paragraph description of what this accessibility report covers, who it is for, and the time window it reports on.

    +
    +
    +

    Details

    +

    Replace this paragraph with the substantive body of the accessibility report. Use semantic markup — lists, tables, sections — instead of flat prose.

    +
    - \ No newline at end of file + diff --git a/templates/skeletons/api-documentation.html b/templates/skeletons/api-documentation.html index 68ee5f8..13ecfde 100644 --- a/templates/skeletons/api-documentation.html +++ b/templates/skeletons/api-documentation.html @@ -1,21 +1,56 @@ - + + - + -Api Documentation +API Documentation — Bloom skeleton -

    Api Documentation

    Generated: placeholder date

    +
    +

    API Documentation

    +

    Replace with a real date — e.g. May 19, 2026

    +
    -

    Overview

    Template for api documentation content.

    +

    Skeleton template. Replace each data-template slot with project-specific content before publishing. See ../../docs/construction-rules.md for the rules every Bloom artifact must satisfy.

    +
    +

    Overview

    +

    Replace this starter summary with a one-paragraph description of what this api documentation covers, who it is for, and the time window it reports on.

    +
    +
    +

    Details

    +

    Replace this paragraph with the substantive body of the api documentation. Use semantic markup — lists, tables, sections — instead of flat prose.

    +
    - \ No newline at end of file + diff --git a/templates/skeletons/architecture-decision.html b/templates/skeletons/architecture-decision.html index c38c5eb..41fdf25 100644 --- a/templates/skeletons/architecture-decision.html +++ b/templates/skeletons/architecture-decision.html @@ -1,21 +1,56 @@ - + + - + -Architecture Decision +Architecture Decision — Bloom skeleton -

    Architecture Decision

    Generated: placeholder date

    +
    +

    Architecture Decision

    +

    Replace with a real date — e.g. May 19, 2026

    +
    -

    Overview

    Template for architecture decision content.

    +

    Skeleton template. Replace each data-template slot with project-specific content before publishing. See ../../docs/construction-rules.md for the rules every Bloom artifact must satisfy.

    +
    +

    Overview

    +

    Replace this starter summary with a one-paragraph description of what this architecture decision covers, who it is for, and the time window it reports on.

    +
    +
    +

    Details

    +

    Replace this paragraph with the substantive body of the architecture decision. Use semantic markup — lists, tables, sections — instead of flat prose.

    +
    - \ No newline at end of file + diff --git a/templates/skeletons/dependency-audit.html b/templates/skeletons/dependency-audit.html index f33c52e..350594b 100644 --- a/templates/skeletons/dependency-audit.html +++ b/templates/skeletons/dependency-audit.html @@ -1,21 +1,56 @@ - + + - + -Dependency Audit +Dependency Audit — Bloom skeleton -

    Dependency Audit

    Generated: placeholder date

    +
    +

    Dependency Audit

    +

    Replace with a real date — e.g. May 19, 2026

    +
    -

    Overview

    Template for dependency audit content.

    +

    Skeleton template. Replace each data-template slot with project-specific content before publishing. See ../../docs/construction-rules.md for the rules every Bloom artifact must satisfy.

    +
    +

    Overview

    +

    Replace this starter summary with a one-paragraph description of what this dependency audit covers, who it is for, and the time window it reports on.

    +
    +
    +

    Details

    +

    Replace this paragraph with the substantive body of the dependency audit. Use semantic markup — lists, tables, sections — instead of flat prose.

    +
    - \ No newline at end of file + diff --git a/templates/skeletons/design-review.html b/templates/skeletons/design-review.html index 08c5940..39acc10 100644 --- a/templates/skeletons/design-review.html +++ b/templates/skeletons/design-review.html @@ -1,21 +1,56 @@ - + + - + -Design Review +Design Review — Bloom skeleton -

    Design Review

    Generated: placeholder date

    +
    +

    Design Review

    +

    Replace with a real date — e.g. May 19, 2026

    +
    -

    Overview

    Template for design review content.

    +

    Skeleton template. Replace each data-template slot with project-specific content before publishing. See ../../docs/construction-rules.md for the rules every Bloom artifact must satisfy.

    +
    +

    Overview

    +

    Replace this starter summary with a one-paragraph description of what this design review covers, who it is for, and the time window it reports on.

    +
    +
    +

    Details

    +

    Replace this paragraph with the substantive body of the design review. Use semantic markup — lists, tables, sections — instead of flat prose.

    +
    - \ No newline at end of file + diff --git a/templates/skeletons/migration-plan.html b/templates/skeletons/migration-plan.html index b5aa261..2e55bd7 100644 --- a/templates/skeletons/migration-plan.html +++ b/templates/skeletons/migration-plan.html @@ -1,21 +1,56 @@ - + + - + -Migration Plan +Migration Plan — Bloom skeleton -

    Migration Plan

    Generated: placeholder date

    +
    +

    Migration Plan

    +

    Replace with a real date — e.g. May 19, 2026

    +
    -

    Overview

    Template for migration plan content.

    +

    Skeleton template. Replace each data-template slot with project-specific content before publishing. See ../../docs/construction-rules.md for the rules every Bloom artifact must satisfy.

    +
    +

    Overview

    +

    Replace this starter summary with a one-paragraph description of what this migration plan covers, who it is for, and the time window it reports on.

    +
    +
    +

    Details

    +

    Replace this paragraph with the substantive body of the migration plan. Use semantic markup — lists, tables, sections — instead of flat prose.

    +
    - \ No newline at end of file + diff --git a/templates/skeletons/monthly-review.html b/templates/skeletons/monthly-review.html index a2bf316..d23d00d 100644 --- a/templates/skeletons/monthly-review.html +++ b/templates/skeletons/monthly-review.html @@ -1,21 +1,56 @@ - + + - + -Monthly Review +Monthly Review — Bloom skeleton -

    Monthly Review

    Generated: placeholder date

    +
    +

    Monthly Review

    +

    Replace with a real date — e.g. May 19, 2026

    +
    -

    Overview

    Template for monthly review content.

    +

    Skeleton template. Replace each data-template slot with project-specific content before publishing. See ../../docs/construction-rules.md for the rules every Bloom artifact must satisfy.

    +
    +

    Overview

    +

    Replace this starter summary with a one-paragraph description of what this monthly review covers, who it is for, and the time window it reports on.

    +
    +
    +

    Details

    +

    Replace this paragraph with the substantive body of the monthly review. Use semantic markup — lists, tables, sections — instead of flat prose.

    +
    - \ No newline at end of file + diff --git a/templates/skeletons/onboarding-guide.html b/templates/skeletons/onboarding-guide.html index 1e3c87a..6ed08dc 100644 --- a/templates/skeletons/onboarding-guide.html +++ b/templates/skeletons/onboarding-guide.html @@ -1,21 +1,56 @@ - + + - + -Onboarding Guide +Onboarding Guide — Bloom skeleton -

    Onboarding Guide

    Generated: placeholder date

    +
    +

    Onboarding Guide

    +

    Replace with a real date — e.g. May 19, 2026

    +
    -

    Overview

    Template for onboarding guide content.

    +

    Skeleton template. Replace each data-template slot with project-specific content before publishing. See ../../docs/construction-rules.md for the rules every Bloom artifact must satisfy.

    +
    +

    Overview

    +

    Replace this starter summary with a one-paragraph description of what this onboarding guide covers, who it is for, and the time window it reports on.

    +
    +
    +

    Details

    +

    Replace this paragraph with the substantive body of the onboarding guide. Use semantic markup — lists, tables, sections — instead of flat prose.

    +
    - \ No newline at end of file + diff --git a/templates/skeletons/sprint-retro.html b/templates/skeletons/sprint-retro.html index 1c185a7..ce72b2a 100644 --- a/templates/skeletons/sprint-retro.html +++ b/templates/skeletons/sprint-retro.html @@ -1,21 +1,56 @@ - + + - + -Sprint Retro +Sprint Retro — Bloom skeleton -

    Sprint Retro

    Generated: placeholder date

    +
    +

    Sprint Retro

    +

    Replace with a real date — e.g. May 19, 2026

    +
    -

    Overview

    Template for sprint retro content.

    +

    Skeleton template. Replace each data-template slot with project-specific content before publishing. See ../../docs/construction-rules.md for the rules every Bloom artifact must satisfy.

    +
    +

    Overview

    +

    Replace this starter summary with a one-paragraph description of what this sprint retro covers, who it is for, and the time window it reports on.

    +
    +
    +

    Details

    +

    Replace this paragraph with the substantive body of the sprint retro. Use semantic markup — lists, tables, sections — instead of flat prose.

    +
    - \ No newline at end of file + diff --git a/templates/skeletons/weekly-digest.html b/templates/skeletons/weekly-digest.html index b745ccc..9b32e0d 100644 --- a/templates/skeletons/weekly-digest.html +++ b/templates/skeletons/weekly-digest.html @@ -1,21 +1,56 @@ - + + - + -Weekly Digest +Weekly Digest — Bloom skeleton -

    Weekly Digest

    Generated: placeholder date

    +
    +

    Weekly Digest

    +

    Replace with a real date — e.g. May 19, 2026

    +
    -

    Overview

    Template for weekly digest content.

    +

    Skeleton template. Replace each data-template slot with project-specific content before publishing. See ../../docs/construction-rules.md for the rules every Bloom artifact must satisfy.

    +
    +

    Overview

    +

    Replace this starter summary with a one-paragraph description of what this weekly digest covers, who it is for, and the time window it reports on.

    +
    +
    +

    Details

    +

    Replace this paragraph with the substantive body of the weekly digest. Use semantic markup — lists, tables, sections — instead of flat prose.

    +
    - \ No newline at end of file + diff --git a/templates/status-report.html b/templates/status-report.html index 1f9c32f..6cf520d 100644 --- a/templates/status-report.html +++ b/templates/status-report.html @@ -8,7 +8,7 @@ :root { --ivory:#FAF9F5;--slate:#141413;--clay:#D97757;--oat:#E3DACC;--olive:#788C5D; --rust:#B04A3F;--gray-100:#F0EEE6;--gray-300:#D1CFC5;--gray-500:#87867F; - --gray-700:#3D3D3A;--white:#FFFFFF; + --gray-700:#3D3D3A;--white:#FFFFFF;--sand:#B89B6E; --serif:ui-serif,Georgia,serif;--sans:system-ui,-apple-system,sans-serif; --mono:ui-monospace,"SF Mono",Menlo,monospace; } @@ -37,11 +37,18 @@ tbody tr:hover{background:var(--ivory)} .risk{display:inline-flex;align-items:center;gap:7px;font-size:12px;color:var(--gray-500)} .risk-dot{width:9px;height:9px;border-radius:50%;flex-shrink:0} -.risk-dot.low{background:var(--olive)}.risk-dot.med{background:#B89B6E}.risk-dot.high{background:var(--clay)} +.risk-dot.low{background:var(--olive)}.risk-dot.med{background:var(--sand)}.risk-dot.high{background:var(--clay)} .highlights{list-style:none;padding:0} .highlights li{position:relative;padding:0 0 14px 26px;font-size:15px;color:var(--gray-700)} .highlights li::before{content:"";position:absolute;left:6px;top:8px;width:7px;height:7px;border-radius:2px;background:var(--clay)} .highlights li strong{color:var(--slate);font-weight:600} +a:focus-visible,button:focus-visible{outline:2px solid var(--clay);outline-offset:2px;border-radius:4px} +@media print{ + body{background:var(--ivory);color:var(--slate);padding:24px} + .auto-pill{display:none} + section{break-inside:avoid} + a{color:var(--slate);text-decoration:underline} +} @@ -53,6 +60,7 @@

    [PROJECT] — Week [NUM]

    [DATE RANGE]
    +
    @@ -81,6 +89,7 @@

    Shipped

    +
    From 1b765fcb683140161b46c963d539d362104ebff0 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 15:32:05 +0000 Subject: [PATCH 3/5] Rewrite install docs around what works today, add CI and release process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit README and docs/harness-setup.md previously led every harness section with a marketplace install command — most of those listings are not live yet ("after submission", "after listing lands"). A first-time reader would copy a command that fails before they ever discovered the manual install buried as a fallback. Flip the order. Every harness section now leads with the manual install, which works today against the harness's current release. Speculative marketplace commands move to a clearly labeled "Planned marketplace install — not yet live" subsection. The README's file tree is regenerated from the actual filesystem (removing names like design-system-reference.html, animation-sandbox.html, triage-board.html, etc. that did not exist on disk), the validator section lists the 10 rules that the registry actually loads, and the construction-rules summary picks up the new rule 7 wording. Add .github/workflows/ci.yml so every push and PR runs: - the validator's own 12-test node:test suite - bloom-validate over templates/*.html - bloom-validate over templates/skeletons/*.html - bloom-validate over examples/*.html A green CI run is now a precondition for cutting a release. Add docs/public-readiness.md with the truth/install/validation/demo/ out-of-box checklist this repo holds itself to before a public release, and docs/release-checklist.md with the per-release process — version bumps across the three version-bearing files, the audit script, the release-branch flow, tagging, and rollback procedure. --- .github/workflows/ci.yml | 30 +++++ README.md | 255 ++++++++++++++++++++++---------------- docs/harness-setup.md | 158 +++++++++-------------- docs/public-readiness.md | 69 +++++++++++ docs/release-checklist.md | 91 ++++++++++++++ 5 files changed, 400 insertions(+), 203 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 docs/public-readiness.md create mode 100644 docs/release-checklist.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b05ad19 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,30 @@ +name: CI + +on: + push: + branches: [main, master] + pull_request: + +jobs: + validator: + name: bloom-validator tests + artifact validation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Run validator unit tests + working-directory: bloom-validator + run: npm test + + - name: Validate templates + run: node bloom-validator/src/index.ts templates/*.html + + - name: Validate skeletons + run: node bloom-validator/src/index.ts templates/skeletons/*.html + + - name: Validate examples + run: node bloom-validator/src/index.ts examples/*.html diff --git a/README.md b/README.md index f784278..b6c94a5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **Bloom** is a per-session sticky skill that makes flat markdown bloom into rich, self-contained `.html` artifacts. Drop it into any AI coding agent and reports, reviews, plans, design docs, and interactive editors come back as single `.html` files you can open, click around, and export from — because diffs, diagrams, status reports, and design comparisons are **spatial** information that loses meaning when flattened into prose. -Supported harnesses: +Supported harnesses (the skill is a single markdown file; copy it to whatever your agent reads): - **Claude Code** — `.claude/skills/bloom/` (sticky session skill) - **Codex CLI** (OpenAI) — `AGENTS.md` @@ -34,143 +34,140 @@ Type `/bloom` once and every substantial artifact for the rest of the session be This skill captures the patterns from [The Unreasonable Effectiveness of HTML](https://thariqs.github.io/html-effectiveness/) and makes them reproducible across every agent harness. +See [`examples/`](examples/) for worked artifacts: + +- [`pr-review-example.html`](examples/pr-review-example.html) — annotated PR review with risk chips, per-file cards, and a next-steps checklist +- [`incident-report-example.html`](examples/incident-report-example.html) — SEV-2 postmortem with timeline, root cause, impact, and action items +- [`design-system-example.html`](examples/design-system-example.html) — living token reference with copyable color chips and a composed preview + --- ## Installation Installation differs by harness. If you use more than one, install Bloom separately for each one. Each install is sticky once activated in a session and stays on until you turn it off or the session ends. -### Claude Code +**Every harness section below leads with the manual install — it works today, with no marketplace dependency.** A "Planned marketplace install" subsection is included where one is being prepared, clearly marked as not yet live. -Bloom is shipped as a Claude Code plugin via the **Bloom marketplace** and is queued for submission to Anthropic's official plugin marketplace. +### Claude Code -**Anthropic Official Marketplace** (after submission lands) +**Works today: manual install** -- Install the plugin from Anthropic's official marketplace: +Copy the packaged skill into your project (or `~/.claude/skills/`): +```bash +cp -r .claude/skills/bloom /path/to/your-project/.claude/skills/bloom ``` -/plugin install bloom@claude-plugins-official -``` - -**Bloom Marketplace** - -The Bloom marketplace provides Bloom and any future related plugins for Claude Code. -- Register the marketplace: +Or drop the whole plugin into a project that uses `.claude-plugin/`: -``` -/plugin marketplace add SunnyDevendranadh/Bloom +```bash +cp -r plugins/bloom /path/to/your-project/.claude/plugins/bloom ``` -- Install the plugin from this marketplace: +Activate per session with `/bloom`, `/bloom-on`, or by saying "bloom on" / "let it bloom". Deactivate with `/bloom-off`. -``` -/plugin install bloom@bloom -``` +**Planned marketplace install** — not yet live -Activate per session with `/bloom`, `/bloom-on`, or by saying "bloom on" / "let it bloom" in any message. Deactivate with `/bloom-off`. +Bloom is queued for submission to Anthropic's official plugin marketplace. Until then, prefer the manual install above. The local Bloom marketplace listing also exists (`.claude-plugin/marketplace.json`); once Anthropic's marketplace ingestion is live for community plugins, this will be a one-liner. Do not paste speculative `/plugin install` commands until that listing is verified. ### Codex CLI -Bloom is queued for submission to the [official Codex plugin marketplace](https://github.com/openai/plugins). +**Works today: manual install** -- Open the plugin search interface: - -``` -/plugins +```bash +cp droids/bloom.md /path/to/your-project/AGENTS.md +# or, globally: +cp droids/bloom.md ~/.codex/AGENTS.md ``` -- Search for Bloom: +If you already have an `AGENTS.md`, append the contents of `droids/bloom.md` to it instead of replacing it. -``` -bloom -``` +**Planned marketplace install** — not yet live -- Select `Install Plugin`. - -**Manual install** (works today): copy `droids/bloom.md` to your repo's `AGENTS.md` or `~/.codex/AGENTS.md`. +Bloom is planned for submission to the [openai/plugins](https://github.com/openai/plugins) marketplace. Until that listing exists, use the manual install above. ### Codex App -Bloom is queued for submission to the [official Codex plugin marketplace](https://github.com/openai/plugins). +**Works today: manual install** -- In the Codex app, click on **Plugins** in the sidebar. -- You should see `Bloom` in the Coding section. -- Click the `+` next to Bloom and follow the prompts. +Commit `AGENTS.md` (copied from `droids/bloom.md`) to the GitHub branch you connect to the Codex app: -**Manual install** (works today): commit `AGENTS.md` (copied from `droids/bloom.md`) to the GitHub branch you connect to Codex. +```bash +cp droids/bloom.md AGENTS.md +git add AGENTS.md && git commit -m "Add Bloom skill" && git push +``` -### Factory Droid +**Planned marketplace install** — not yet live -- Register the marketplace: +Once Bloom is listed in the Codex app's plugin sidebar, install will be a single click. Until then, use the manual install above. -``` -droid plugin marketplace add https://github.com/SunnyDevendranadh/Bloom -``` +### Factory Droid -- Install the plugin: +**Works today: manual install** -``` -droid plugin install bloom@bloom +```bash +# Project-scoped: +mkdir -p .factory/droids && cp droids/bloom.md .factory/droids/ +# Personal: +mkdir -p ~/.factory/droids && cp droids/bloom.md ~/.factory/droids/ ``` -**Manual install** (works today): `cp droids/bloom.md ~/.factory/droids/` (personal) or `.factory/droids/` (project). +**Planned marketplace install** — not yet live + +Once Bloom is published to a Factory plugin marketplace, register and install will be a two-liner. Not live yet. ### Gemini CLI -- Install the extension: +**Works today: manual install** -``` -gemini extensions install https://github.com/SunnyDevendranadh/Bloom +```bash +cp droids/bloom.md GEMINI.md +# or globally: +cp droids/bloom.md ~/.gemini/GEMINI.md ``` -- Update later: +**Planned marketplace install** — not yet live -``` -gemini extensions update bloom -``` - -**Manual install** (works today): copy `droids/bloom.md` to `GEMINI.md` at the repo root or `~/.gemini/GEMINI.md` global. +`gemini extensions install ` may work for some Gemini CLI builds, but the install path has not been validated against the current Gemini CLI release. Until verified, use the manual install above. ### OpenCode -OpenCode uses its own plugin install; install Bloom separately even if you already use it in another harness. - -- Tell OpenCode: +**Works today: manual install** +```bash +cp droids/bloom.md /path/to/your-project/AGENTS.md ``` -Fetch and follow instructions from https://raw.githubusercontent.com/SunnyDevendranadh/Bloom/main/plugins/bloom/INSTALL.opencode.md -``` -**Manual install** (works today): copy `droids/bloom.md` to your repo's `AGENTS.md`. +Optional helper: ask OpenCode itself to follow [`plugins/bloom/INSTALL.opencode.md`](plugins/bloom/INSTALL.opencode.md). + +**Planned marketplace install** — not yet live + +OpenCode's plugin marketplace ingestion is evolving; once a verified install exists, it will replace this manual step. ### Cursor -- In Cursor Agent chat, install from the marketplace: +**Works today: manual install** -``` -/add-plugin bloom +```bash +mkdir -p .cursor/rules && cp droids/bloom.md .cursor/rules/bloom.mdc +# or paste the contents of droids/bloom.md into .cursorrules ``` -- Or search for "bloom" in the plugin marketplace. +**Planned marketplace install** — not yet live -**Manual install** (works today): copy `droids/bloom.md` to `.cursor/rules/bloom.mdc` or paste the bloom snippet into `.cursorrules`. +If/when Cursor exposes a `/add-plugin bloom` command, it will be added here. Not live yet. ### GitHub Copilot CLI -- Register the marketplace: +**Works today: manual install** -``` -copilot plugin marketplace add SunnyDevendranadh/Bloom +```bash +cp droids/bloom.md /path/to/your-project/AGENTS.md ``` -- Install the plugin: - -``` -copilot plugin install bloom@bloom -``` +**Planned marketplace install** — not yet live -**Manual install** (works today): copy `droids/bloom.md` to your repo's `AGENTS.md`. +Copilot's plugin marketplace install path has not been verified. Use the manual install above. ### Other harnesses @@ -233,46 +230,62 @@ Bloom/ ├── .claude/ │ └── skills/ │ └── bloom/ -│ └── SKILL.md # Claude Code skill (manual install / self-use) +│ └── SKILL.md # Claude Code skill (manual install) ├── droids/ -│ └── bloom.md # The canonical skill (Factory droid + universal) +│ └── bloom.md # Canonical cross-harness skill ├── docs/ │ ├── harness-setup.md # Per-agent setup guides │ ├── categories.md # The 9 document categories explained -│ ├── design-system.md # Full token reference (v1) +│ ├── design-system.md # Token reference (v1) │ ├── design-system-v2.md # Dark mode, motion tokens, Tabs, Modal -│ ├── construction-rules.md # The 12 rules for producing HTML (v1) +│ ├── construction-rules.md # The 12 rules for producing HTML │ ├── construction-rules-v2.md # Rule 9 revision for templates -│ └── security.md # Security hardening guide -├── bloom-validator/ # Zero-dep TypeScript CLI for the 12+8 rules +│ ├── security.md # Security hardening guide +│ ├── public-readiness.md # Public-readiness checklist +│ └── release-checklist.md # Release process +├── bloom-validator/ # Zero-dep TypeScript CLI │ ├── README.md │ ├── package.json │ ├── src/ │ │ ├── index.ts # CLI entry (bloom-validate) │ │ ├── parser.ts │ │ ├── reporter.ts +│ │ ├── rule-registry.ts # All active rules in one place │ │ └── rules/ # One file per rule │ └── tests/ # node:test suite + fixtures -├── templates/ -│ ├── exploration-code-approaches.html +├── templates/ # Production-quality templates │ ├── annotated-pr-review.html -│ ├── design-system-reference.html -│ ├── animation-sandbox.html -│ ├── annotated-flowchart.html -│ ├── slide-deck.html -│ ├── feature-explainer.html -│ ├── status-report.html -│ ├── status-report-v2.html # Worked v2 example (data-template slots) +│ ├── exploration-code-approaches.html │ ├── incident-timeline.html -│ ├── triage-board.html -│ ├── feature-flag-editor.html -│ └── prompt-tuner.html -└── examples/ - ├── pr-review-example.html - ├── incident-report-example.html - └── design-system-example.html +│ ├── status-report.html +│ ├── status-report-v2.html +│ └── skeletons/ # Starter scaffolds (clearly labeled) +│ ├── accessibility-report.html +│ ├── api-documentation.html +│ ├── architecture-decision.html +│ ├── dependency-audit.html +│ ├── design-review.html +│ ├── migration-plan.html +│ ├── monthly-review.html +│ ├── onboarding-guide.html +│ ├── sprint-retro.html +│ └── weekly-digest.html +├── examples/ # Fully worked artifacts +│ ├── pr-review-example.html +│ ├── incident-report-example.html +│ └── design-system-example.html +└── .github/ + └── workflows/ + └── ci.yml # Validator tests + artifact validation ``` +Templates and skeletons are different: + +- **Templates** (`templates/*.html`) are production-quality. Real semantic structure, print styles, focus styles, ready to drop content into. +- **Skeletons** (`templates/skeletons/*.html`) are starter scaffolds. Each opens with a comment marking it as a skeleton and uses `data-template=""` markers instead of placeholder text. Replace the slots before publishing. + +Every file in `templates/` and `examples/` passes [`bloom-validator`](bloom-validator/). + --- ## The 9 document categories @@ -293,7 +306,7 @@ Bloom/ ## Design system -All templates use CSS custom properties from the same warm palette. See [`docs/design-system.md`](docs/design-system.md) for the full v1 reference and [`docs/design-system-v2.md`](docs/design-system-v2.md) for dark-mode tokens (via `prefers-color-scheme`), motion tokens (durations + easings), and the Tabs / Modal component patterns. +All templates use CSS custom properties from the same warm palette. See [`docs/design-system.md`](docs/design-system.md) for the full reference and [`docs/design-system-v2.md`](docs/design-system-v2.md) for dark-mode tokens (via `prefers-color-scheme`), motion tokens (durations + easings), and the Tabs / Modal component patterns. | Token | Value | Usage | |---|---|---| @@ -330,25 +343,50 @@ All templates follow the security guidelines in [`docs/security.md`](docs/securi - No `data:` URIs for executable content - All event handlers use `addEventListener`, not inline `on*` attributes +The validator enforces all of these via the `security-hardening` rule. + --- ## Validation -[`bloom-validator/`](bloom-validator/) is a zero-dependency TypeScript CLI that checks any `.html` file against Bloom's construction and security rules. It uses Node ≥ 22.6 native TypeScript type-stripping — no build step. +[`bloom-validator/`](bloom-validator/) is a zero-dependency TypeScript CLI that checks any `.html` file against Bloom's construction and security rules. It uses Node ≥ 22.6 native TypeScript type-stripping — no build step, no dependencies. ```bash +# Validate a single file node bloom-validator/src/index.ts path/to/file.html + +# JSON output node bloom-validator/src/index.ts path/to/file.html --json + +# Multiple files at once node bloom-validator/src/index.ts a.html b.html c.html + +# Validate every template and example in this repo +node bloom-validator/src/index.ts templates/*.html templates/skeletons/*.html examples/*.html ``` -Exit codes: `0` clean, `1` errors found, `2` invalid usage. See [`bloom-validator/README.md`](bloom-validator/README.md) for the full rule table and JSON output shape. +Exit codes: `0` clean, `1` errors found, `2` invalid usage. + +The validator currently enforces 10 rules: + +- `no-external-deps` +- `no-hardcoded-hex` +- `semantic-html` +- `print-media-query` +- `heading-hierarchy` +- `viewport-meta` +- `no-dialog-apis` +- `lang-attribute` +- `focus-visible` +- `security-hardening` (bundles `no-eval`, `innerHTML-with-variable`, `no-network`, `no-inline-handlers`, `no-data-html-uri`, `no-javascript-uri`, and two more — see [`bloom-validator/README.md`](bloom-validator/README.md)) + +Every template under `templates/` and every artifact under `examples/` passes this validator on every push (see [`.github/workflows/ci.yml`](.github/workflows/ci.yml)). --- ## Construction rules -See [`docs/construction-rules.md`](docs/construction-rules.md) for the full 12-rule checklist, and [`docs/construction-rules-v2.md`](docs/construction-rules-v2.md) for the Rule 9 revision that lets templates ship plausible default content with `data-template=""` markers instead of `[BRACKET]` placeholders. Summary: +See [`docs/construction-rules.md`](docs/construction-rules.md) for the full checklist, and [`docs/construction-rules-v2.md`](docs/construction-rules-v2.md) for the Rule 9 revision that lets templates ship plausible default content with `data-template=""` markers instead of `[BRACKET]` placeholders. Summary: 1. **Single file** — All HTML, CSS, JS in one `.html` file 2. **CSS custom properties** — Use the palette tokens, never hard-code colors @@ -356,9 +394,9 @@ See [`docs/construction-rules.md`](docs/construction-rules.md) for the full 12-r 4. **Inline JS only** — Minimal, no frameworks, no build step 5. **Responsive** — `max-width` wrappers, `clamp()` type, `@media` breakpoints 6. **Export mechanism** — "Copy as markdown/JSON/diff" button on every editor -7. **Print-friendly** — Key content readable without JS +7. **Print-friendly** — Key content readable without JS; `@media print` block 8. **Accessible** — `aria-label`, `role`, heading hierarchy, focus states -9. **No placeholder content** — Every word specific and real +9. **No placeholder content** — Every word specific and real (or marked via `data-template=`) 10. **Viewport meta** — Always include `` 11. **Progressive enhancement** — Core content visible without JS 12. **No `alert()`/`prompt()`/`confirm()`** — Use inline UI @@ -370,8 +408,17 @@ See [`docs/construction-rules.md`](docs/construction-rules.md) for the full 12-r 1. Fork this repo 2. Create a feature branch 3. Add or improve templates, docs, or the skill itself -4. Make sure templates pass the construction rules checklist -5. Open a PR +4. Run the validator against any HTML you change: + ```bash + node bloom-validator/src/index.ts templates/*.html examples/*.html + ``` +5. Run the validator's own tests: + ```bash + cd bloom-validator && npm test + ``` +6. Open a PR + +See [`docs/public-readiness.md`](docs/public-readiness.md) for the checklist this repo holds itself to, and [`docs/release-checklist.md`](docs/release-checklist.md) for the per-release process. --- diff --git a/docs/harness-setup.md b/docs/harness-setup.md index 8aeb34d..fcbdfa6 100644 --- a/docs/harness-setup.md +++ b/docs/harness-setup.md @@ -2,26 +2,42 @@ How to install **Bloom** — the per-session sticky HTML skill — for every major AI coding agent. -Bloom is sticky: once activated in a session, it stays on until the session ends or the user deactivates it. Each harness section below shows the marketplace install command (where available), the manual install path as a fallback, plus the activation and deactivation triggers. +Bloom is sticky: once activated in a session, it stays on until the session ends or the user deactivates it. **Every harness section leads with the manual install — it works today.** Marketplace commands are listed under "Planned marketplace install" where one is in flight; they are deliberately not the primary recommendation until verified live. --- -## Marketplace install (recommended) +## Manual install (primary path for every harness) -For harnesses with a plugin/extension marketplace, the cleanest install is via the marketplace command. The README has the per-harness one-liners; this section is the deep reference for each. +The single source of truth for the skill is [`droids/bloom.md`](../droids/bloom.md). Every harness install is some variation of copying that file into the location the harness reads. -| Harness | Marketplace install | +| Harness | Manual install | |---|---| -| Claude Code | `/plugin install bloom@claude-plugins-official` (official, after submission) or `/plugin marketplace add SunnyDevendranadh/Bloom` + `/plugin install bloom@bloom` | -| Codex CLI | `/plugins` → search "bloom" → Install (after submission to openai/plugins) | -| Codex App | Sidebar → Plugins → click `+` on Bloom (after submission to openai/plugins) | -| Factory Droid | `droid plugin marketplace add https://github.com/SunnyDevendranadh/Bloom` + `droid plugin install bloom@bloom` | -| Gemini CLI | `gemini extensions install https://github.com/SunnyDevendranadh/Bloom` | -| OpenCode | "Fetch and follow https://raw.githubusercontent.com/SunnyDevendranadh/Bloom/main/plugins/bloom/INSTALL.opencode.md" | -| Cursor | `/add-plugin bloom` (after marketplace listing) | -| GitHub Copilot CLI | `copilot plugin marketplace add SunnyDevendranadh/Bloom` + `copilot plugin install bloom@bloom` | +| Claude Code | `cp -r .claude/skills/bloom /path/to/project/.claude/skills/bloom` | +| Codex CLI | `cp droids/bloom.md /path/to/project/AGENTS.md` | +| Codex App | `cp droids/bloom.md AGENTS.md && git commit && git push` | +| Factory Droid | `cp droids/bloom.md .factory/droids/` | +| Gemini CLI | `cp droids/bloom.md GEMINI.md` | +| OpenCode | `cp droids/bloom.md /path/to/project/AGENTS.md` | +| Cursor | `cp droids/bloom.md .cursor/rules/bloom.mdc` | +| GitHub Copilot CLI | `cp droids/bloom.md /path/to/project/AGENTS.md` | -If a marketplace listing isn't live yet for your harness, every harness also has a manual install — see its section below. +Per-harness deep notes are in each section below. + +## Planned marketplace installs (not yet live) + +A marketplace listing is being prepared for several harnesses. Until each one is verified working against the harness's current release, do **not** paste the corresponding command — use the manual install above. + +| Harness | Status | +|---|---| +| Claude Code | Queued for Anthropic's official plugin marketplace. Local `.claude-plugin/marketplace.json` exists but ingestion path not yet verified. | +| Codex CLI / Codex App | Queued for `openai/plugins`. Not live. | +| Factory Droid | Plugin marketplace install path not yet verified against current Factory CLI. | +| Gemini CLI | `gemini extensions install ` may work on some builds; not verified against the current Gemini CLI release. | +| OpenCode | Marketplace ingestion is evolving; helper at [`plugins/bloom/INSTALL.opencode.md`](../plugins/bloom/INSTALL.opencode.md). | +| Cursor | No verified `/add-plugin` flow yet. | +| GitHub Copilot CLI | Plugin marketplace install path not yet verified. | + +When a listing goes live and is end-to-end verified, it gets promoted out of this section and into the primary install path. --- @@ -92,49 +108,27 @@ That snippet is what the per-harness sections below repeat. If you've already do ## Claude Code -**Recommended: install via plugin marketplace.** - -Bloom ships as a Claude Code plugin and is queued for submission to Anthropic's official plugin marketplace. - -``` -# After submission lands -/plugin install bloom@claude-plugins-official -``` - -Or install from the Bloom marketplace today: - -``` -/plugin marketplace add SunnyDevendranadh/Bloom -/plugin install bloom@bloom -``` - -The plugin packages the bloom skill so it loads automatically into every Claude Code session in workspaces that have it installed. Activate per session with `/bloom`, `/bloom-on`, or by saying "bloom on" / "let it bloom". Deactivate with `/bloom-off`. - -**Alternative: install as a raw skill** (no plugin system). Copy the `.claude/skills/bloom/` directory into your project (or `~/.claude/skills/` for global use): +**Works today: install as a raw skill.** Copy the `.claude/skills/bloom/` directory into your project (or `~/.claude/skills/` for global use): ```bash -# Project skill (this repo only) +# Project skill (one repo) cp -r .claude/skills/bloom/ /path/to/your-project/.claude/skills/ -# Global skill (all your Claude Code sessions) +# Global skill (every Claude Code session you start) cp -r .claude/skills/bloom/ ~/.claude/skills/ ``` +Activate per session with `/bloom`, `/bloom-on`, or by saying "bloom on" / "let it bloom". Deactivate with `/bloom-off`. + **Alternative: add to `CLAUDE.md`** (project) or `~/.claude/CLAUDE.md` (global). Paste the AGENTS.md snippet from the universal section above. +**Planned marketplace install — not yet live.** Bloom is queued for Anthropic's official plugin marketplace. A local Bloom marketplace listing (`.claude-plugin/marketplace.json`) exists in this repo, but ingestion against the current Claude Code release has not been verified end-to-end. Do not paste `/plugin install bloom@…` commands until that is confirmed working. + --- ## Codex CLI (OpenAI) -**Recommended: install via the [official Codex plugin marketplace](https://github.com/openai/plugins)** (after submission lands): - -``` -/plugins -``` - -Search for `bloom` and select **Install Plugin**. - -**Manual install** (works today): the Codex CLI reads `AGENTS.md` at the repo root and `~/.codex/AGENTS.md` for global instructions. +**Works today: manual install.** The Codex CLI reads `AGENTS.md` at the repo root and `~/.codex/AGENTS.md` for global instructions. ```bash # Project-level bloom (this repo only) @@ -147,17 +141,13 @@ cp droids/bloom.md ~/.codex/AGENTS.md If `AGENTS.md` already exists in either location, append the universal AGENTS.md snippet from the section above. Bloom activates the first time the user message in a Codex CLI session contains `/bloom`, "bloom on", or "let it bloom". +**Planned marketplace install — not yet live.** Bloom is planned for submission to the [openai/plugins](https://github.com/openai/plugins) marketplace. Until that listing is verified working against the current Codex CLI release, use the manual install above. + --- ## Codex App (OpenAI web / desktop) -**Recommended: install via the [official Codex plugin marketplace](https://github.com/openai/plugins)** (after submission lands): - -- In the Codex App, click on **Plugins** in the sidebar. -- You should see `Bloom` in the Coding section. -- Click the `+` next to Bloom and follow the prompts. - -**Manual install** (works today): the Codex App reads `AGENTS.md` from the GitHub repository it's connected to. +**Works today: manual install.** The Codex App reads `AGENTS.md` from the GitHub repository it's connected to. 1. Commit `AGENTS.md` to your repo root (copy `droids/bloom.md` or paste the universal snippet). 2. Push to the branch you connect to Codex. @@ -165,46 +155,31 @@ If `AGENTS.md` already exists in either location, append the universal AGENTS.md Bloom stays sticky for the rest of that Codex App task. To auto-activate without typing a trigger, commit a `.bloom` file at the repo root. +**Planned marketplace install — not yet live.** Once Bloom is listed in the Codex app's plugin sidebar, install will be a single click. Until then, use the manual install above. + --- ## Factory Droid -**Recommended: install via the Factory Droid plugin marketplace.** - -``` -droid plugin marketplace add https://github.com/SunnyDevendranadh/Bloom -droid plugin install bloom@bloom -``` - -**Manual install** (works today): +**Works today: manual install.** ```bash # Personal — applies to all your projects -cp droids/bloom.md ~/.factory/droids/ +mkdir -p ~/.factory/droids && cp droids/bloom.md ~/.factory/droids/ # Project — applies to one project only -cp droids/bloom.md .factory/droids/ +mkdir -p .factory/droids && cp droids/bloom.md .factory/droids/ ``` Then invoke the `bloom` droid in your session. +**Planned marketplace install — not yet live.** Once Bloom is published to a Factory plugin marketplace, register and install will be a two-liner. Until that path is verified against the current Factory CLI, use the manual install above. + --- ## Gemini CLI (Google) -**Recommended: install via the Gemini CLI extensions system.** - -``` -gemini extensions install https://github.com/SunnyDevendranadh/Bloom -``` - -Update later with: - -``` -gemini extensions update bloom -``` - -**Manual install** (works today): the Gemini CLI reads `GEMINI.md` at the repo root and `~/.gemini/GEMINI.md` for global instructions. +**Works today: manual install.** The Gemini CLI reads `GEMINI.md` at the repo root and `~/.gemini/GEMINI.md` for global instructions. ```bash # Project-level bloom @@ -217,19 +192,13 @@ cp droids/bloom.md ~/.gemini/GEMINI.md If `GEMINI.md` already exists, paste the universal AGENTS.md snippet from above at the top — the trigger phrases work identically in Gemini CLI. A `.bloom` file at the repo root auto-activates bloom at session start. +**Planned extensions install — not yet verified.** `gemini extensions install ` may work on some Gemini CLI builds, but the install path has not been validated against the current release. Until verified, use the manual install above. + --- ## OpenCode (sst) -OpenCode uses its own plugin install. Install Bloom separately even if you already use it in another harness. - -**Recommended: tell OpenCode to fetch the install doc:** - -``` -Fetch and follow instructions from https://raw.githubusercontent.com/SunnyDevendranadh/Bloom/main/plugins/bloom/INSTALL.opencode.md -``` - -Or use the same flow as the Codex CLI manual install — OpenCode reads `AGENTS.md` at the repo root: +**Works today: manual install.** OpenCode reads `AGENTS.md` at the repo root. ```bash # Project-level @@ -238,25 +207,21 @@ cp droids/bloom.md /path/to/your-project/AGENTS.md If you also use OpenCode's `opencode.json` for project config, the AGENTS.md install is independent — bloom triggers work regardless of the JSON config. A `.bloom` file at the repo root auto-activates bloom. +**Optional helper.** You can also ask OpenCode itself to follow [`plugins/bloom/INSTALL.opencode.md`](../plugins/bloom/INSTALL.opencode.md) — that prompt walks the agent through the same manual install above. + --- ## Cursor -**Recommended: install via the Cursor plugin marketplace** (after listing lands): - -``` -/add-plugin bloom -``` - -Or search for "bloom" in the Cursor plugin marketplace. - -**Manual install — newer Cursor (`.cursor/rules/*.mdc`):** +**Works today: manual install (newer Cursor, `.cursor/rules/*.mdc`):** ```bash mkdir -p /path/to/your-project/.cursor/rules cp droids/bloom.md /path/to/your-project/.cursor/rules/bloom.mdc ``` +**Planned marketplace install — not yet live.** If/when Cursor exposes a `/add-plugin bloom` command and Bloom is listed in their marketplace, it will be added here. Until then, use the manual install above. + **Manual install — legacy Cursor (`.cursorrules` at the repo root):** Paste this snippet into `.cursorrules`: @@ -282,14 +247,7 @@ For every .html produced: ## GitHub Copilot CLI -**Recommended: install via the GitHub Copilot CLI plugin marketplace.** - -``` -copilot plugin marketplace add SunnyDevendranadh/Bloom -copilot plugin install bloom@bloom -``` - -**Manual install** (works today): the GitHub Copilot CLI reads `AGENTS.md` at the repo root. Copy `droids/bloom.md` there: +**Works today: manual install.** The GitHub Copilot CLI reads `AGENTS.md` at the repo root. Copy `droids/bloom.md` there: ```bash cp droids/bloom.md /path/to/your-project/AGENTS.md @@ -301,6 +259,8 @@ Trigger bloom in the CLI by typing `/bloom` or saying "bloom on" / "let it bloom A `.bloom` file at the repo root auto-activates bloom for any new Copilot CLI session in that workspace. +**Planned marketplace install — not yet live.** Copilot CLI's plugin marketplace install path has not been verified. Use the manual install above. + --- ## GitHub Copilot for VS Code diff --git a/docs/public-readiness.md b/docs/public-readiness.md new file mode 100644 index 0000000..89cd287 --- /dev/null +++ b/docs/public-readiness.md @@ -0,0 +1,69 @@ +# Public-readiness checklist + +What this repo holds itself to before any version is announced. The goal is **truthful, installable, validated, demonstrable, and useful out of the box**. + +Every public release must pass every item below. If an item is failing, fix the underlying issue — don't dilute the bar. + +--- + +## Truthful + +- [ ] Every install command shown in `README.md` is either verified to work today, or clearly marked as **"Planned marketplace install — not yet live"**. +- [ ] The file tree in `README.md` matches the actual filesystem (no listed files that don't exist; no real files missing from the listing). +- [ ] Every rule cited in `README.md` and `bloom-validator/README.md` is actually present in `bloom-validator/src/rule-registry.ts`. +- [ ] No template, skeleton, or example contains the strings `Lorem`, `placeholder date`, `TODO` (outside intentional `data-template` slots), or `Template for content`. +- [ ] No rule file imports a function that doesn't exist (regression-tested by `npm test` failing at import time). +- [ ] No `.md` doc references a path that does not exist on disk. + +## Installable + +- [ ] Each supported harness has a **manual install** path documented as the primary install method. +- [ ] The manual install for each harness has been performed end-to-end at least once and produced an `.html` artifact. +- [ ] If a marketplace install is shown, it has been verified against the latest release of that harness within the last 30 days. Unverified marketplace commands are removed or moved under "Planned". +- [ ] `cp droids/bloom.md /path/to/AGENTS.md` works for any AGENTS.md-aware harness. + +## Validated + +- [ ] `cd bloom-validator && npm test` passes locally on Node ≥ 22.6. +- [ ] `node bloom-validator/src/index.ts templates/*.html` exits 0. +- [ ] `node bloom-validator/src/index.ts templates/skeletons/*.html` exits 0. +- [ ] `node bloom-validator/src/index.ts examples/*.html` exits 0. +- [ ] `.github/workflows/ci.yml` is green on the release commit. +- [ ] Every rule in `rule-registry.ts` has at least one fixture under `bloom-validator/tests/fixtures/`. + +## Demonstrable + +- [ ] `examples/` contains at least three fully worked artifacts that match named categories in `docs/categories.md`. +- [ ] Each example renders correctly when opened from `file://` in Chrome, Safari, and Firefox. +- [ ] Each example prints to a single column with readable text and no broken layout. +- [ ] No example produces a console error or fails CSP defaults. + +## Useful out of the box + +- [ ] A first-time user can install Bloom for at least one harness in under 3 minutes following only `README.md`. +- [ ] After install, typing `/bloom` (or saying "bloom on") in that harness activates the skill on the next turn without further setup. +- [ ] At least one example artifact in `examples/` is referenced from the README so the user can see the deliverable before installing. +- [ ] `templates/skeletons/` and `templates/` are visibly distinguished in the README, and each skeleton's leading comment makes its purpose clear. + +--- + +## How to run the full audit locally + +```bash +# 1. Validator unit tests +cd bloom-validator && npm test && cd .. + +# 2. All artifacts +node bloom-validator/src/index.ts \ + templates/*.html \ + templates/skeletons/*.html \ + examples/*.html + +# 3. Repo-tree drift check (manual) +git ls-files templates/ examples/ docs/ bloom-validator/src/rules/ + +# 4. Scan for placeholder leakage +grep -RIn --include='*.html' -E '\b(Lorem|placeholder date|TODO|Template for)' templates/ examples/ || echo "clean" +``` + +All four steps must succeed before a public-readiness audit is considered green. diff --git a/docs/release-checklist.md b/docs/release-checklist.md new file mode 100644 index 0000000..ee9e2ba --- /dev/null +++ b/docs/release-checklist.md @@ -0,0 +1,91 @@ +# Release checklist + +The process for tagging a new Bloom release. + +--- + +## Pre-flight + +1. Pick the version. Bloom follows [SemVer](https://semver.org/): + - **Major** — breaking change to the skill's expected user contract (activation trigger removed, default output directory changed, validator rule made an error after being a warning). + - **Minor** — additive: new template, new validator rule, new docs section, new harness support. + - **Patch** — bug fix only. Validator parser fix, template typo, doc clarification. +2. Decide a one-line headline for the release. Write it before changing any file — if you can't write the headline, the scope isn't right yet. + +## Audit + +Run the full public-readiness audit (see [`public-readiness.md`](public-readiness.md)) and confirm every item is green. + +```bash +cd bloom-validator && npm test && cd .. +node bloom-validator/src/index.ts templates/*.html templates/skeletons/*.html examples/*.html +grep -RIn --include='*.html' -E '\b(Lorem|placeholder date|TODO|Template for)' templates/ examples/ || echo "clean" +``` + +If any step fails, fix the underlying issue and re-run. **Never patch the audit script to make a release pass.** + +## Update version-bearing files + +| File | What to update | +|---|---| +| `bloom-validator/package.json` | `version` field | +| `.claude-plugin/marketplace.json` | Bloom plugin entry's `version` | +| `plugins/bloom/.claude-plugin/plugin.json` | `version` field | + +Keep all three in lockstep. + +## Update CHANGELOG (if present) and commit + +If a `CHANGELOG.md` exists, add a section for the new version with: + +- **Added** — new templates, new validator rules, new harness support, new docs +- **Changed** — non-breaking refactors a user might notice +- **Fixed** — bug fixes +- **Removed** — only if user-visible + +Commit on the release branch: + +```bash +git checkout -b release/vX.Y.Z +# … edit version files … +git add -A +git commit -m "Release vX.Y.Z" +``` + +## Open and merge the release PR + +1. Open a PR titled `Release vX.Y.Z — `. +2. Wait for [`.github/workflows/ci.yml`](../.github/workflows/ci.yml) to be green. +3. Get one approving review. +4. Merge to `main` with a merge commit (not squash) so the release boundary is preserved. + +## Tag + +```bash +git checkout main +git pull origin main +git tag -a vX.Y.Z -m "Bloom vX.Y.Z — " +git push origin vX.Y.Z +``` + +## Cut the GitHub release + +Use the tag. Paste the headline as the release title. Paste the relevant CHANGELOG section as the body. Attach no binaries — Bloom is plain text. + +## Post-release + +- Update any pinned marketplace listings (if/when one goes live) to point at the new tag. +- If a harness's marketplace listing is now verified working, move it from "Planned marketplace install" to the primary install path in `README.md`. +- Open issues for any roadmap rules under "Planned (not yet enforced)" in `bloom-validator/README.md` that have a clearer design after this release. + +--- + +## Rollback + +If a release ships a regression that affects users (validator false-positives in a common pattern, skill activation broken in a harness): + +1. Revert the merge commit on `main`. +2. Cut a patch release (`vX.Y.Z+1`) with the revert. +3. Note the rollback in the next release's CHANGELOG. + +Do not force-push to `main` and do not delete the broken tag — leaving it visible is more honest than hiding it. From 4c9fa1e8210c4c4aa8fbfa4b153d41ba18e2cd40 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 15:39:28 +0000 Subject: [PATCH 4/5] Remove TODO leak from pr-review-example.html A review-comment bubble in the PR review example used the literal word TODO in user-facing text, which the public-readiness checklist explicitly bans ("No template, skeleton, or example contains the strings Lorem, placeholder date, TODO ..."). The release-checklist grep would have flagged this on the next release attempt. Replace the meta phrasing with a concrete review note that fits the example's narrative: the second test case asserts only the happy path and needs the cache-expiry branch added before merge. grep -RIn -E '\b(Lorem|placeholder date|TODO|Template for)' templates/ examples/ is now clean. Validator still reports zero issues. --- examples/pr-review-example.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/pr-review-example.html b/examples/pr-review-example.html index 67f512c..b3d903d 100644 --- a/examples/pr-review-example.html +++ b/examples/pr-review-example.html @@ -209,7 +209,7 @@

    Files

    L78
    -

    Note Second test stub is currently TODO — fill in before merge.

    +

    Note Second test case currently asserts only the happy path; add the cache-expiry branch before merge.

    From ee82409e3c1df48c0861eeb54283ac84737d9805 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 15:43:18 +0000 Subject: [PATCH 5/5] Add npm run validate-all so artifact validation works on every shell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous invocation — node bloom-validator/src/index.ts templates/*.html templates/skeletons/*.html examples/*.html — relied on shell glob expansion, which silently fails on PowerShell and CMD. Windows contributors would see the validator look for a literal file named templates/*.html and exit 2. Add bloom-validator/scripts/validate-all.mjs that: - resolves the file list in Node via readdirSync over a fixed set of artifact directories (templates, templates/skeletons, examples) - derives the validator path from import.meta.url, so it works whether invoked via npm run validate-all (cwd = bloom-validator) or directly as node bloom-validator/scripts/validate-all.mjs from any cwd - propagates the validator's exit code Wire it up as `npm run validate-all` and use it everywhere the three-line shell invocation appeared: - .github/workflows/ci.yml replaces three separate steps with one - README.md "Validation" + "Contributing" point to the new command - docs/public-readiness.md audit script uses it - docs/release-checklist.md audit collapses to two lines - bloom-validator/README.md documents npm test and npm run validate-all as the canonical commands Verified end-to-end: npm test still 12/12, npm run validate-all reports 18 clean artifacts and exits 0. --- .github/workflows/ci.yml | 11 ++---- README.md | 9 +++-- bloom-validator/README.md | 10 ++++- bloom-validator/package.json | 3 +- bloom-validator/scripts/validate-all.mjs | 49 ++++++++++++++++++++++++ docs/public-readiness.md | 11 +++--- docs/release-checklist.md | 3 +- 7 files changed, 74 insertions(+), 22 deletions(-) create mode 100644 bloom-validator/scripts/validate-all.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b05ad19..0e511e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,11 +20,6 @@ jobs: working-directory: bloom-validator run: npm test - - name: Validate templates - run: node bloom-validator/src/index.ts templates/*.html - - - name: Validate skeletons - run: node bloom-validator/src/index.ts templates/skeletons/*.html - - - name: Validate examples - run: node bloom-validator/src/index.ts examples/*.html + - name: Validate every template, skeleton, and example + working-directory: bloom-validator + run: npm run validate-all diff --git a/README.md b/README.md index b6c94a5..a17f2fa 100644 --- a/README.md +++ b/README.md @@ -361,8 +361,9 @@ node bloom-validator/src/index.ts path/to/file.html --json # Multiple files at once node bloom-validator/src/index.ts a.html b.html c.html -# Validate every template and example in this repo -node bloom-validator/src/index.ts templates/*.html templates/skeletons/*.html examples/*.html +# Validate every template, skeleton, and example in this repo +# (Node resolves the file list, so this works on Bash, Zsh, PowerShell, and CMD.) +cd bloom-validator && npm run validate-all ``` Exit codes: `0` clean, `1` errors found, `2` invalid usage. @@ -408,9 +409,9 @@ See [`docs/construction-rules.md`](docs/construction-rules.md) for the full chec 1. Fork this repo 2. Create a feature branch 3. Add or improve templates, docs, or the skill itself -4. Run the validator against any HTML you change: +4. Run the validator against every template, skeleton, and example: ```bash - node bloom-validator/src/index.ts templates/*.html examples/*.html + cd bloom-validator && npm run validate-all ``` 5. Run the validator's own tests: ```bash diff --git a/bloom-validator/README.md b/bloom-validator/README.md index 9f2086e..4a2ce3a 100644 --- a/bloom-validator/README.md +++ b/bloom-validator/README.md @@ -80,11 +80,19 @@ When multiple files are passed, the top level is an array of these objects. ## Running tests ```bash -node --test tests/validator.test.ts +npm test ``` 12 tests under [`tests/`](tests/) cover one passing file (`valid.html`), one false-positive guard (`valid-with-urls.html`), and one targeted failure fixture per rule family. +## Validating every template, skeleton, and example + +```bash +npm run validate-all +``` + +This runs [`scripts/validate-all.mjs`](scripts/validate-all.mjs), which resolves the artifact list in Node (not via shell globbing) and shells out to `bloom-validate` once with every file. It works identically on Bash, Zsh, PowerShell, and CMD — useful for Windows contributors, and the single canonical command CI uses too. + ## Notes on the inline template `