Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,6 @@ jobs:

- name: Run test suite
run: pytest -v

- name: Verify SEO Metadata & Artifacts
run: python3 scripts/test_seo.py
68 changes: 65 additions & 3 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="HowlCreate is the computational creativity, ideation, and open-ended problem-solving layer of the Howl ecosystem, turning ambiguous challenges into lineage-tracked concepts.">
<meta name="description" content="HowlCreate is the computational creativity and ideation layer of the Howl ecosystem, turning ambiguous engineering problems into lineage-tracked concepts.">
<link rel="canonical" href="https://howlcipher.github.io/howlcreate/">

<!-- Open Graph Metadata -->
Expand All @@ -24,6 +24,30 @@
<meta name="twitter:image" content="https://howlcipher.github.io/howlcreate/social-preview.png">
<meta name="twitter:image:alt" content="HowlCreate computational creativity and concept lineage preview card">

<!-- JSON-LD Structured Data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "HowlCreate",
"applicationCategory": "DeveloperApplication",
"operatingSystem": "POSIX, Linux, macOS",
"description": "Computational creativity and ideation layer turning ambiguous challenges into lineage-tracked concepts through multi-operator search and assumption challenging.",
"url": "https://howlcipher.github.io/howlcreate/",
"softwareVersion": "0.1.0-dev",
"author": {
"@type": "Person",
"name": "William Elias",
"url": "https://howlcipher.github.io/william_elias/"
},
"isPartOf": {
"@type": "SoftwareApplication",
"name": "Howl Autonomous Software Engineering Ecosystem",
"url": "https://howlcipher.github.io/howl/"
}
}
</script>

<title>HowlCreate | Computational Creativity &amp; Ideation Layer</title>
<link rel="stylesheet" href="style.css">
<link rel="icon" type="image/svg+xml" href="favicon.svg">
Expand Down Expand Up @@ -115,7 +139,7 @@
</a>
</div>
<div class="drawer-footer">
<span>● 8 PRODUCTION &amp; CONTINUITY NODES</span>
<span>● 9 PRODUCTION NODES</span>
<span>AUTH // HOWL 2026</span>
</div>
</aside>
Expand Down Expand Up @@ -148,6 +172,7 @@
<a href="#why-create">02_WhyItExists</a>
<a href="#boundary">03_HowlPlaneBoundary</a>
<a href="#operators">04_CreativeOperators</a>
<a href="#ideation-qa">04B_IdeationFAQ</a>
<a href="#pipeline">05_ExplorationWorkflow</a>
<a href="#status-cli">06_StatusAndCLI</a>
</nav>
Expand All @@ -166,7 +191,7 @@
<p class="hero-kicker">// creative reasoning / open-ended exploration / concept lineage</p>
<h1 id="main-title" class="hero-title">HowlCreate <span class="jp-sub">クリエイト // 2026</span></h1>
<p class="hero-lead">
HowlCreate helps turn imagination, ideas, ambiguity, and open-ended problems into rigorous concepts that can be explored, refined, challenged, and handed into the rest of the Howl ecosystem.
Designed and engineered by <a href="https://howlcipher.github.io/william_elias/" style="color: var(--color-amber); text-decoration: underline;">William Elias</a> as part of the <a href="https://howlcipher.github.io/howl/" style="color: var(--color-amber); text-decoration: underline;">Howl Ecosystem</a>, HowlCreate helps turn imagination, ideas, ambiguity, and open-ended problems into rigorous concepts that can be explored, refined, challenged, and handed into the rest of the Howl ecosystem.
</p>
</div>

Expand Down Expand Up @@ -363,6 +388,42 @@ <h3>06 // Adversarial Critique &amp; Brittleness</h3>
</div>
</section>

<!-- 04B Computational Creativity & Speculative Ideation Q&A -->
<section id="ideation-qa" class="tech-panel">
<div class="tech-header">
<h2><span class="sec-id">SECTION // 04B</span> Technical Q&amp;A: Computational Creativity &amp; Speculative Ideation</h2>
<span class="subsystem-tag">HCRT-MOD-CREATIVE-QA</span>
</div>
<div class="tech-body">
<div class="faq-group">
<div class="faq-item" style="margin-bottom: 1.5rem; padding: 1rem; border-left: 3px solid var(--color-amber); background: var(--color-surface);">
<h3 style="margin-top: 0; font-size: 1.1rem; color: var(--color-amber);">How does computational creativity differ from random LLM brainstorming?</h3>
<p>
Standard LLM prompting produces superficial, consensus-biased ideas that mimic the training distribution's most frequent answers. Computational creativity in HowlCreate introduces structured search operators: explicit premise extraction, constraint relaxation, morphological cross-domain synthesis, and formal fitness evaluation. Rather than accepting the first plausible completion, HowlCreate maps the conceptual search space systematically.
</p>
</div>
<div class="faq-item" style="margin-bottom: 1.5rem; padding: 1rem; border-left: 3px solid var(--color-blue); background: var(--color-surface);">
<h3 style="margin-top: 0; font-size: 1.1rem; color: var(--color-blue);">Why is concept lineage and assumption inversion critical before execution planning?</h3>
<p>
When software engineering tasks are handed directly to execution agents without rigorous problem framing, agents optimize for the wrong goals or build fragile workarounds around false constraints. By logging explicit concept lineage DAGs and inverting implicit premises (e.g. questioning whether agents need direct git push rights), engineers uncover fundamentally simpler architectural paradigms before a single line of production code is written.
</p>
</div>
<div class="faq-item" style="margin-bottom: 1.5rem; padding: 1rem; border-left: 3px solid var(--color-green); background: var(--color-surface);">
<h3 style="margin-top: 0; font-size: 1.1rem; color: var(--color-green);">How does HowlCreate isolate speculative prototypes from production control planes?</h3>
<p>
HowlCreate possesses zero mutation authority over production git branches, release gates, or repository remotes. Its outputs are purely epistemic artifacts: lineage trees, assumption registers, and evaluated concept proposals. These concepts must undergo independent human review and pass into HowlPlane and HowlChangeOps before becoming executable task plans.
</p>
</div>
<div class="faq-item" style="margin-bottom: 1.5rem; padding: 1rem; border-left: 3px solid var(--color-red); background: var(--color-surface);">
<h3 style="margin-top: 0; font-size: 1.1rem; color: var(--color-red);">What role do divergent operators play in safe autonomous software engineering?</h3>
<p>
Divergent operators force the generation of mutually isolated solution candidates across orthogonal architectural axes. This prevents premature convergence on local optima and enables adversarial falsifiers to stress-test radically different approaches against operational risk, latency, and maintainability metrics.
</p>
</div>
</div>
</div>
</section>

<!-- 05 Exploration Workflow -->
<section id="pipeline" class="tech-panel">
<div class="tech-header">
Expand Down Expand Up @@ -455,6 +516,7 @@ <h2><span class="sec-id">SECTION // 06</span> Current Status, Installation &amp;
</div>
<div class="footer-links">
<nav class="footer-nav" aria-label="Ecosystem Links">
<a href="https://howlcipher.github.io/william_elias/">William Elias Portfolio</a>
<a href="https://howlcipher.github.io/howl/">Howl Hub</a>
<a href="https://howlcipher.github.io/howlcreate/">HowlCreate</a>
<a href="https://howlcipher.github.io/howlframe/">HowlFrame</a>
Expand Down
4 changes: 4 additions & 0 deletions docs/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
User-agent: *
Allow: /

Sitemap: https://howlcipher.github.io/howlcreate/sitemap.xml
9 changes: 9 additions & 0 deletions docs/sitemap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://howlcipher.github.io/howlcreate/</loc>
<lastmod>2026-09-07</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
</urlset>
137 changes: 137 additions & 0 deletions scripts/test_seo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#!/usr/bin/env python3
"""
SEO & Search Discoverability Verification Suite for HowlCreate.
Validates structured data, canonical tags, sitemap, robots.txt, and entity linking.
"""

import os
import re
import sys
import json
import xml.etree.ElementTree as ET

REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DOCS_DIR = os.path.join(REPO_ROOT, "docs")
INDEX_HTML = os.path.join(DOCS_DIR, "index.html")
ROBOTS_TXT = os.path.join(DOCS_DIR, "robots.txt")
SITEMAP_XML = os.path.join(DOCS_DIR, "sitemap.xml")

def test_seo():
print("=== Running HowlCreate SEO Verification ===")

# 1. Check docs/index.html
assert os.path.exists(INDEX_HTML), f"Missing {INDEX_HTML}"
with open(INDEX_HTML, "r", encoding="utf-8") as f:
html = f.read()

# Title check
title_match = re.search(r"<title>(.*?)</title>", html, re.IGNORECASE | re.DOTALL)
assert title_match, "Missing <title> tag in index.html"
title = title_match.group(1).strip()
assert "HowlCreate" in title, f"Title does not mention HowlCreate: {title}"
print(f" [PASS] HTML <title> exists: {title}")

# Meta description check
meta_desc_match = re.search(
r'<meta\s+name=["\']description["\']\s+content=["\'](.*?)["\']',
html,
re.IGNORECASE,
)
assert meta_desc_match, "Missing meta description in index.html"
meta_desc = meta_desc_match.group(1).strip()
assert len(meta_desc) > 30, "Meta description too short"
assert len(meta_desc) <= 170, f"Meta description exceeds 170 chars ({len(meta_desc)}): {meta_desc}"
print(f" [PASS] meta description exists: {meta_desc[:60]}... ({len(meta_desc)} chars)")

# Canonical URL check
canonical_match = re.search(
r'<link\s+rel=["\']canonical["\']\s+href=["\'](.*?)["\']',
html,
re.IGNORECASE,
)
assert canonical_match, "Missing link rel=canonical in index.html"
canonical_url = canonical_match.group(1).strip()
expected_canonical = "https://howlcipher.github.io/howlcreate/"
assert canonical_url == expected_canonical, (
f"Canonical URL mismatch: expected {expected_canonical}, got {canonical_url}"
)
print(f" [PASS] Canonical URL matches: {canonical_url}")

# Heading hierarchy check
h1_matches = re.findall(r"<h1[^>]*>(.*?)</h1>", html, re.IGNORECASE | re.DOTALL)
assert len(h1_matches) == 1, f"Expected exactly 1 <h1> tag, found {len(h1_matches)}"
clean_h1 = re.sub(r"<[^>]+>", "", h1_matches[0]).strip()
print(f" [PASS] Exactly 1 H1 present: {clean_h1}")

# Open Graph & Twitter Cards
assert 'property="og:title"' in html or "property='og:title'" in html, "Missing og:title"
assert 'property="og:description"' in html or "property='og:description'" in html, "Missing og:description"
assert 'property="og:url"' in html or "property='og:url'" in html, "Missing og:url"
assert 'name="twitter:card"' in html or "name='twitter:card'" in html, "Missing twitter:card"
print(" [PASS] Open Graph and Twitter card tags verified")

# JSON-LD Schema.org Structured Data
json_ld_matches = re.findall(
r'<script\s+type=["\']application/ld\+json["\']\s*>(.*?)</script>',
html,
re.IGNORECASE | re.DOTALL,
)
assert len(json_ld_matches) >= 1, "Missing JSON-LD structured data block"
ld = json.loads(json_ld_matches[0].strip())
assert ld.get("@context") in ("https://schema.org", "http://schema.org"), "Invalid @context"
ld_type = ld.get("@type")
assert ld_type == "SoftwareApplication", (
f"Expected SoftwareApplication, got {ld_type}"
)
author = ld.get("author", {})
expected_author = "William" + " " + "Elias"
assert author.get("name") == expected_author, (
f"Author name must be {expected_author}"
)
author_url = author.get("url")
expected_author_url = "https://howlcipher.github.io/william_elias/"
assert author_url == expected_author_url, (
"Author URL must point to william_elias portfolio"
)
print(f" [PASS] JSON-LD valid and correctly attributes {expected_author}")

# Internal entity links
william_url = "https://howlcipher.github.io/william_elias/"
assert william_url in html, f"Missing link to William Elias portfolio ({william_url})"
howl_url = "https://howlcipher.github.io/howl/"
assert howl_url in html, f"Missing link to Howl hub ({howl_url})"
print(" [PASS] Internal entity links to William Elias and Howl verified")

# 2. Check docs/robots.txt
assert os.path.exists(ROBOTS_TXT), f"Missing {ROBOTS_TXT}"
with open(ROBOTS_TXT, "r", encoding="utf-8") as f:
robots = f.read()
assert "User-agent: *" in robots, "robots.txt missing User-agent: *"
assert "Allow: /" in robots, "robots.txt missing Allow: /"
assert "Sitemap: https://howlcipher.github.io/howlcreate/sitemap.xml" in robots, (
"robots.txt missing correct Sitemap directive"
)
print(" [PASS] docs/robots.txt valid and references sitemap")

# 3. Check docs/sitemap.xml
assert os.path.exists(SITEMAP_XML), f"Missing {SITEMAP_XML}"
tree = ET.parse(SITEMAP_XML)
root = tree.getroot()
namespace = {"sm": "http://www.sitemaps.org/schemas/sitemap/0.9"}
locs = [elem.text.strip() for elem in root.findall(".//sm:loc", namespace)]
assert expected_canonical in locs, (
f"sitemap.xml does not contain canonical URL {expected_canonical}"
)
print(f" [PASS] docs/sitemap.xml valid and contains canonical URL")

print("\nAll SEO validations PASSED successfully!\n")

if __name__ == "__main__":
try:
test_seo()
except AssertionError as e:
print(f"FAIL: {e}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"ERROR: {e}", file=sys.stderr)
sys.exit(1)
Loading