<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>Hacks/Hackers | Technology + Journalism</title>
        <link rel="stylesheet" href="https://www.hackshackers.com/assets/built/screen.css?v=0e87d094ad">
    <meta name="description" content="Where journalists and technologists build together to strengthen public information, through events, hands-on AI programs and open-source tools">
    <link rel="icon" href="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w256h256/2024/05/hackshackers_logomark.png" type="image/png">
    <link rel="canonical" href="https://www.hackshackers.com/">
    <meta name="referrer" content="no-referrer-when-downgrade">
    <link rel="next" href="https://www.hackshackers.com/page/2/">
    
    <meta property="og:site_name" content="Hacks/Hackers">
    <meta property="og:type" content="website">
    <meta property="og:title" content="Hacks/Hackers">
    <meta property="og:description" content="Advancing media innovation to foster public trust">
    <meta property="og:url" content="https://www.hackshackers.com/">
    <meta property="og:image" content="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w1200/2024/08/IMG_1580.jpg">
    <meta property="article:publisher" content="https://www.facebook.com/hackshackers">
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:title" content="Hacks/Hackers">
    <meta name="twitter:description" content="Where journalists and technologists build together to strengthen public information, through events, hands-on AI programs and open-source tools">
    <meta name="twitter:url" content="https://www.hackshackers.com/">
    <meta name="twitter:image" content="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w1200/2024/08/IMG_1580.jpg">
    <meta property="og:image:width" content="1200">
    <meta property="og:image:height" content="900">
    
    <script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "WebSite",
    "publisher": {
        "@type": "Organization",
        "name": "Hacks/Hackers",
        "url": "https://www.hackshackers.com/",
        "logo": {
            "@type": "ImageObject",
            "url": "https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2024/05/hackshackers_logotype-horizontal.png"
        }
    },
    "url": "https://www.hackshackers.com/",
    "name": "Hacks/Hackers",
    "image": {
        "@type": "ImageObject",
        "url": "https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w1200/2024/08/IMG_1580.jpg",
        "width": 1200,
        "height": 900
    },
    "mainEntityOfPage": "https://www.hackshackers.com/",
    "description": "Where journalists and technologists build together to strengthen public information, through events, hands-on AI programs and open-source tools"
}
    </script>

    <meta name="generator" content="Ghost 6.50">
    <link rel="alternate" type="application/rss+xml" title="Hacks/Hackers" href="https://www.hackshackers.com/rss/">
    <script defer src="https://cdn.jsdelivr.net/ghost/portal@~2.69/umd/portal.min.js" data-i18n="true" data-ghost="https://www.hackshackers.com/" data-key="3d4f533c5b64ef61c44067313d" data-api="https://hacks-hackers.ghost.io/ghost/api/content/" data-locale="en" crossorigin="anonymous"></script><style id="gh-members-styles">.gh-post-upgrade-cta-content,
.gh-post-upgrade-cta {
    display: flex;
    flex-direction: column;
    align-items: center;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
    text-align: center;
    width: 100%;
    color: #ffffff;
    font-size: 16px;
}

.gh-post-upgrade-cta-content {
    border-radius: 8px;
    padding: 40px 4vw;
}

.gh-post-upgrade-cta h2 {
    color: #ffffff;
    font-size: 28px;
    letter-spacing: -0.2px;
    margin: 0;
    padding: 0;
}

.gh-post-upgrade-cta p {
    margin: 20px 0 0;
    padding: 0;
}

.gh-post-upgrade-cta small {
    font-size: 16px;
    letter-spacing: -0.2px;
}

.gh-post-upgrade-cta a {
    color: #ffffff;
    cursor: pointer;
    font-weight: 500;
    box-shadow: none;
    text-decoration: underline;
}

.gh-post-upgrade-cta a:hover {
    color: #ffffff;
    opacity: 0.8;
    box-shadow: none;
    text-decoration: underline;
}

.gh-post-upgrade-cta a.gh-btn {
    display: block;
    background: #ffffff;
    text-decoration: none;
    margin: 28px 0 0;
    padding: 8px 18px;
    border-radius: 4px;
    font-size: 16px;
    font-weight: 600;
}

.gh-post-upgrade-cta a.gh-btn:hover {
    opacity: 0.92;
}</style><script async src="https://js.stripe.com/v3/"></script>
    <script defer src="https://cdn.jsdelivr.net/ghost/sodo-search@~1.8/umd/sodo-search.min.js" data-key="3d4f533c5b64ef61c44067313d" data-styles="https://cdn.jsdelivr.net/ghost/sodo-search@~1.8/umd/main.css" data-sodo-search="https://hacks-hackers.ghost.io/" data-locale="en" crossorigin="anonymous"></script>
    
    <link href="https://www.hackshackers.com/webmentions/receive/" rel="webmention">
    <script defer src="/public/cards.min.js?v=0e87d094ad"></script>
    <link rel="stylesheet" type="text/css" href="/public/cards.min.css?v=0e87d094ad">
    <script defer src="/public/member-attribution.min.js?v=0e87d094ad"></script>
    <script defer src="/public/ghost-stats.min.js?v=0e87d094ad" data-stringify-payload="false" data-datasource="analytics_events" data-storage="localStorage" data-host="https://www.hackshackers.com/.ghost/analytics/api/v1/page_hit"  tb_site_uuid="a4e737ce-0487-4330-bd5a-4bb2cffab98a" tb_post_uuid="undefined" tb_post_type="null" tb_member_uuid="undefined" tb_member_status="undefined" tb_gift_link=""></script><style>:root {--ghost-accent-color: #0d1312;}</style>
    <!-- fonts are self-hosted in the theme (assets/built/fonts) — do not re-add Google Fonts links; Cloudflare Fonts rewrites them and its Fraunces drops the weight axis -->
<style>
/* Blue callout = editorial preface (italic intro note) */
.post-template .gh-content > .kg-callout-card-blue {
  background: var(--color-lighter-gray, #f6f6f6);
  border: none;
  border-left: 3px solid var(--color-mid-gray, #ccc);
  border-radius: 0;
  padding: 1rem 1.4rem;
  margin: 0 0 2.4rem 0;
}
.post-template .gh-content > .kg-callout-card-blue .kg-callout-emoji {
  display: none;
}
.post-template .gh-content > .kg-callout-card-blue .kg-callout-text {
  font-size: 1.7rem;
  color: var(--color-primary-text, #333);
  line-height: 1.6;
}

/* Paper card for AI Papers Explained metadata — uses <dl>/<dt>/<dd> + CSS Grid */
.post-template .gh-content > .paper-card,
.post-template .gh-content > .kg-card.paper-card,
.post-template .gh-content .kg-card.kg-html-card .paper-card {
  border-top: 1px solid var(--color-light-gray, #e6e6e6);
  border-bottom: 1px solid var(--color-light-gray, #e6e6e6);
  padding: 1.2rem 0;
  margin: 0 0 2.4rem 0;
  font-family: var(--font-sans);
  font-size: 1.5rem;
  line-height: 1.8;
  color: var(--color-primary-text, #333);
  display: grid;
  grid-template-columns: 8rem 1fr;
  column-gap: 0.6rem;
  row-gap: 0;
}
.paper-card dt {
  font-family: 'Chakra Petch', sans-serif;
  font-weight: 600;
  font-size: 0.85em;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-darker-gray, #15171a);
  text-align: right;
  align-self: baseline;
  white-space: nowrap;
}
.paper-card dd {
  margin: 0;
  align-self: baseline;
}

/* Drop cap on first paragraph of post body — excludes newsletters and opt-out tag */
.post-template:not(.tag-newsletter):not(.tag-no-dropcap):not(.tag-hash-no-dropcap) .gh-content > p:first-of-type::first-letter {
  font-family: 'Chakra Petch', sans-serif;
  font-weight: 700;
  font-size: 4.8em;
  line-height: 0.9;
  float: left;
  margin: 0.08em 0.14em 0 -0.05em;
  color: var(--color-darker-gray, #15171a);
}
@media (max-width: 600px) {
  .post-template:not(.tag-newsletter):not(.tag-no-dropcap):not(.tag-hash-no-dropcap) .gh-content > p:first-of-type::first-letter {
    font-size: 3.6em;
  }
}

/* Wrap code blocks to body text width instead of horizontal scroll */
.gh-content pre {
  white-space: pre-wrap;
  overflow-wrap: break-word;
  word-wrap: break-word;
  overflow-x: auto;
}
</style>
</head>

<body class="home-template is-head-left-logo has-serif-body">


<div class="gh-site">
    <header id="gh-head" class="gh-head gh-outer">
        <div class="gh-head-inner gh-inner">
            <div class="gh-head-brand">
                <div class="gh-head-brand-wrapper">
                    <a class="gh-head-logo" href="https://www.hackshackers.com" aria-label="Hacks/Hackers — home">
                            <img src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2024/05/hackshackers_logotype-horizontal.png" alt="Hacks/Hackers">
                    </a>
                </div>
                <button class="gh-search gh-icon-btn" aria-label="Search this site" data-ghost-search><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" width="20" height="20"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg></button>
                <button class="gh-burger"></button>
            </div>

            <nav class="gh-head-menu">
                <ul class="nav">
    <li class="nav-about"><a href="https://www.hackshackers.com/about/">About</a></li>
    <li class="nav-events"><a href="https://www.hackshackers.com/events/">Events</a></li>
    <li class="nav-programs"><a href="https://www.hackshackers.com/programs/">Programs</a></li>
    <li class="nav-support-us"><a href="https://www.hackshackers.com/donate/">Support us</a></li>
    <li class="nav-newsletters"><a href="https://www.hackshackers.com/tag/newsletter/">Newsletters</a></li>
    <li class="nav-connect"><a href="https://www.hackshackers.com/contact/">Connect</a></li>
</ul>

            </nav>

            <div class="gh-head-actions">
                    <button class="gh-search gh-icon-btn" aria-label="Search this site" data-ghost-search><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" width="20" height="20"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg></button>
                    <div class="gh-head-members">
                                <a class="gh-head-btn gh-btn gh-primary-btn" href="#/portal/signup" data-portal="signup">Sign Up</a>
                    </div>
            </div>
        </div>
    </header>

    
<main class="gh-main gh-outer">
    <div class="gh-inner">
        <section class="hero">
            <h1 class="hero-heading">
                Advancing media innovation &amp; fostering public <span class="hero-accent">trust</span>
            </h1>
            <svg class="hero-field" viewBox="0 0 1340 515" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                <defs>
                    <path id="hero-slash" d="M309.123 0.213H206.071L0.878 514.604H103.886L309.123 0.213Z"/>
                </defs>
                <g transform="translate(0 0) scale(0.34 1)"><use class="hero-slash" href="#hero-slash" data-cx="53" data-cy="257" fill="var(--color-ink)" opacity="0.12" style="animation-delay:0s"/></g>
                <g transform="translate(150 0) scale(0.40 1)"><use class="hero-slash" href="#hero-slash" data-cx="212" data-cy="257" fill="var(--color-ink)" opacity="0.22" style="animation-delay:.3s"/></g>
                <g transform="translate(320 0) scale(0.52 1)"><use class="hero-slash" href="#hero-slash" data-cx="401" data-cy="257" fill="var(--color-ink)" opacity="0.40" style="animation-delay:.6s"/></g>
                <g transform="translate(520 0) scale(0.70 1)"><use class="hero-slash" href="#hero-slash" data-cx="629" data-cy="257" fill="var(--color-ink)" opacity="0.62" style="animation-delay:.9s"/></g>
                <g transform="translate(740 0) scale(0.90 1)"><use class="hero-slash" href="#hero-slash" data-cx="880" data-cy="257" fill="var(--color-ink)" opacity="0.92" style="animation-delay:1.2s"/></g>
                <g transform="translate(1010 0) scale(0.78 1)"><use class="hero-slash" href="#hero-slash" data-cx="1131" data-cy="257" fill="var(--color-accent)" opacity="1" style="animation-delay:1.5s"/></g>
            </svg>
            <div class="hero-tail">
                <p class="hero-sub">Since 2009, Hacks/Hackers has brought journalists and technologists together to build the future of news.</p>
                <div class="p-hero-buttons">
                    <a href="/programs/">See our programs &rarr;</a>
                </div>
            </div>
        </section>

        <section class="hero-photos" data-hero-photos aria-label="Scenes from Hacks/Hackers events">
                    <figure class="hp-tile" data-hp-tile><img class="hp-img is-active" loading="eager" fetchpriority="high" src="https://hacks-hackers.ghost.io/content/images/2026/05/hh-hero-new.jpg" alt="Attendees gather in silhouette before a screen showing the Hacks/Hackers AI × Journalism Summit 2026 title slide."></figure>
                    <figure class="hp-tile" data-hp-tile><img class="hp-img is-active" loading="lazy" src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/05/about-1-baltimore-group.jpg" alt="Audience at the Hacks/Hackers AI x Journalism Summit 2025 in Baltimore."></figure>
                    <figure class="hp-tile" data-hp-tile><img class="hp-img is-active" loading="lazy" src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/05/about-3-hackathon-tables.jpg" alt="Participants working at tables during a Hacks/Hackers hackathon."></figure>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/05/about-2-atlantic-group.jpg" data-alt="Hacks/Hackers attendees at a community gathering." hidden></span>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2024/08/IMG_1580-1.jpg" data-alt="Participants at a Hacks/Hackers event." hidden></span>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/07/highres_12604130.jpeg" data-alt="Panel at the first Hacks/Hackers meetup at Freshout in San Francisco, February 2010." hidden></span>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/07/IMG_2216.jpeg" data-alt="Design the Newsroom of 2030 workshop with Hacks/Hackers at ONA 24 in Atlanta, September 2024." hidden></span>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/07/IMG_2226.jpeg" data-alt="Team discussion during the Design the Newsroom of 2030 workshop at ONA 24 in Atlanta, September 2024." hidden></span>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/07/atlantic-hackathon-2026-fireside-chat.jpeg" data-alt="Fireside chat at the 2026 hackathon with The Atlantic and Infactory in East Palo Alto." hidden></span>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/07/hh-workshop-speaker.jpeg" data-alt="Hacks/Hackers co-founder Burt Herman leads a workshop session." hidden></span>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/07/hh-community-hug.jpeg" data-alt="Two community members embrace at a Hacks/Hackers event." hidden></span>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/07/ai-bias-testing-workshop.jpeg" data-alt="Workshop session on testing AI prompts for bias at a Hacks/Hackers event." hidden></span>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/07/ai-journalism-symposium-london.jpeg" data-alt="Presenters on stage at the AI &amp; Journalism Symposium with JournalismAI at Reuters in London." hidden></span>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/07/hh-unite-2010-kqed-crowd.jpg" data-alt="Hacks/Hackers Unite, the first Hacks/Hackers hackathon, at KQED in San Francisco, May 2010." hidden></span>
                    <span data-hp-extra data-src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/2026/07/hh-unite-2010-kqed-tables-overhead.jpg" data-alt="Teams at work during Hacks/Hackers Unite, the first Hacks/Hackers hackathon, at KQED in San Francisco, May 2010." hidden></span>
        </section>

        <section class="features-container">
            <h2 class="features-heading">We do this by:</h2>
            <div class="features-row">
                <div class="feature">
                    <span class="feature-num" aria-hidden="true">1/</span>
                    <p>
                        <span class="bold">Convening summits, forums and hackathons </span>
                        where journalists and technologists learn from each other and shape what comes next.
                    </p>
                </div>
                    <div class="feature">
                    <span class="feature-num" aria-hidden="true">2/</span>
                    <p>
                        <span class="bold">Working directly with newsrooms </span>
                        through our Newsroom AI Lab, from scoping what you need to building it together.
                    </p>
                </div>
                    <div class="feature">
                    <span class="feature-num" aria-hidden="true">3/</span>
                    <p>
                        <span class="bold">Sharing what we learn in the open </span>
                        through our newsletter, our own experiments with new tools and playbooks anyone can use.
                    </p>
                </div>

            </div>

        </section>

        <section class="upcoming" data-upcoming data-upcoming-layout="" hidden aria-labelledby="upcoming-heading">
    <h2 id="upcoming-heading" class="upcoming-heading">Upcoming events</h2>
    <div class="upcoming-body" data-upcoming-body></div>
    <a class="upcoming-all" href="https://luma.com/hackshackers" data-upcoming-all hidden>
        See all events on Luma <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>
    </a>
</section>

<script>
(function () {
  var section = document.querySelector('[data-upcoming]');
  if (!section) return;
  var body = section.querySelector('[data-upcoming-body]');
  var allLink = section.querySelector('[data-upcoming-all]');
  var layout = section.getAttribute('data-upcoming-layout');
  var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  // Defense-in-depth: only ever assign http(s) URLs to src/href (the data is
  // same-origin + normalized, but never let a javascript: URL through).
  function safeUrl(u) { return (typeof u === 'string' && /^https?:\/\//i.test(u)) ? u : null; }

  function fmtDate(iso, tz) {
    try {
      var opts = { month: 'short', day: 'numeric', year: 'numeric' };
      if (tz) opts.timeZone = tz;
      return new Date(iso).toLocaleDateString('en-US', opts);
    } catch (e) { return ''; }
  }

  function cover(ev, cls) {
    var src = safeUrl(ev.coverImage);
    if (src) {
      var img = document.createElement('img');
      img.className = cls + '-img';
      img.src = src;
      img.loading = 'lazy';
      img.alt = ev.title;
      return img;
    }
    // Slash-motif placeholder when an event has no cover.
    var ph = document.createElement('span');
    ph.className = cls + '-img ' + cls + '-placeholder';
    ph.setAttribute('aria-hidden', 'true');
    ph.textContent = '/';
    return ph;
  }

  function metaLine(ev) {
    var p = document.createElement('p');
    p.className = 'uc-meta';
    var t = document.createElement('time');
    t.setAttribute('datetime', ev.startAt);
    t.textContent = fmtDate(ev.startAt, ev.tz);
    p.appendChild(t);
    if (ev.location) {
      var loc = document.createElement('span');
      loc.className = 'uc-loc';
      loc.textContent = ev.location;
      p.appendChild(document.createTextNode(' · '));
      p.appendChild(loc);
    }
    return p;
  }

  function registerLink(ev, label) {
    var a = document.createElement('a');
    a.className = 'uc-register';
    a.href = safeUrl(ev.registerUrl) || '#';
    a.textContent = label;
    a.rel = 'noopener noreferrer';
    a.target = '_blank';
    return a;
  }

  // Full card: cover image + title + meta + description + register.
  // On the homepage the cover art carries the title, so it's hidden unless
  // forceTitle is set (the list view always shows a text title for scanning).
  function featuredCard(ev, forceTitle) {
    var card = document.createElement('article');
    card.className = 'uc-featured';
    card.setAttribute('aria-label', ev.title);
    var media = document.createElement('div');
    media.className = 'uc-featured-media';
    media.appendChild(cover(ev, 'uc-featured'));
    var info = document.createElement('div');
    info.className = 'uc-featured-info';
    if (forceTitle || !safeUrl(ev.coverImage)) {
      var ft = document.createElement('h3');
      ft.className = 'uc-featured-title';
      ft.textContent = ev.title;
      info.appendChild(ft);
    }
    info.appendChild(metaLine(ev));
    // Homepage featured uses the short summary; the events list uses the full
    // description (paragraph breaks preserved), rendered as multiple paragraphs.
    var descText = forceTitle ? (ev.description || ev.summary) : ev.summary;
    if (descText) {
      var paras = forceTitle ? descText.split(/\n+/) : [descText];
      paras.forEach(function (pt) {
        pt = pt.trim();
        if (!pt) return;
        var d = document.createElement('p');
        d.className = 'uc-desc';
        d.textContent = pt;
        info.appendChild(d);
      });
    }
    info.appendChild(registerLink(ev, 'Register →'));
    card.appendChild(media);
    card.appendChild(info);
    return card;
  }

  function sideRow(ev) {
    var row = document.createElement('article');
    row.className = 'uc-side-row';
    var h = document.createElement('h3');
    h.className = 'uc-row-title';
    h.textContent = ev.title;
    row.appendChild(h);
    row.appendChild(metaLine(ev));
    row.appendChild(registerLink(ev, 'Register →'));
    return row;
  }

  function render(data) {
    var events = (data && data.events) || [];
    if (events.length === 0) {
      // Endpoint responded but nothing upcoming: show heading + Luma link only.
      allLink.hidden = false;
      section.hidden = false;
      return;
    }

    if (layout === 'list') {
      // Events page: every event as a full card, stacked in one column.
      events.forEach(function (ev) { body.appendChild(featuredCard(ev, true)); });
      body.appendChild(allLink);
    } else {
      // Homepage: one featured card + a compact side list.
      var featured = events[0];
      var rest = events.slice(1);
      body.appendChild(featuredCard(featured));
      var side = document.createElement('div');
      side.className = 'uc-side';
      rest.forEach(function (ev) { side.appendChild(sideRow(ev)); });
      side.appendChild(allLink);          // Luma link sits at the foot of the side column
      body.appendChild(side);
    }

    allLink.hidden = false;
    if (!reduce) section.classList.add('uc-enter');
    section.hidden = false;
  }

  // Events page lists everything upcoming; the homepage stays a curated few.
  var limit = layout === 'list' ? 20 : 4;
  fetch('/api/events?limit=' + limit, { headers: { accept: 'application/json' } })
    .then(function (r) { if (!r.ok) throw new Error('events ' + r.status); return r.json(); })
    .then(render)
    .catch(function () { /* leave section hidden on hard failure */ });
})();
</script>

        <section class="gh-topic gh-topic-grid">
            <h2 class="gh-topic-name">
                    <a href="https://www.hackshackers.com/posts/">Latest articles</a>
            </h2>

            <div class="gh-topic-content">
                        <article class="gh-card post tag-ai-papers-explained large">
    <a class="gh-card-link" href="/proof-beats-prose/">
            <figure class="gh-card-image">
                <img
                    srcset="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w300/2026/06/proof-beats-prose-abstract.gif 300w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/06/proof-beats-prose-abstract.gif 720w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w960/2026/06/proof-beats-prose-abstract.gif 960w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w1200/2026/06/proof-beats-prose-abstract.gif 1200w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w2000/2026/06/proof-beats-prose-abstract.gif 2000w"
                    sizes="(max-width: 1200px) 100vw, 1200px"
                    src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/06/proof-beats-prose-abstract.gif"
                    alt="Proof beats prose"
                >
            </figure>

        <div class="gh-card-wrapper">
            <header class="gh-card-header">
                <h3 class="gh-card-title">Proof beats prose</h3>
            </header>

                        <div class="gh-card-excerpt">Given the same spreadsheet, an AI wrote the story that showed where every number came from. Readers preferred it to the human version.</div>

            <footer class="gh-card-footer">
                <span class="gh-card-author">Hacks/Hackers AI</span>
                <time class="gh-card-date" datetime="2026-06-26">Jun 26, 2026</time>
            </footer>
        </div>
    </a>
</article>                        <article class="gh-card post tag-ai tag-mcp tag-agents">
    <a class="gh-card-link" href="/how-we-made-our-site-more-readable-for-ai-agents-and-how-you-can-too/">
            <figure class="gh-card-image">
                <img
                    srcset="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w300/2026/06/hi-ai-1200.gif 300w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/06/hi-ai-1200.gif 720w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w960/2026/06/hi-ai-1200.gif 960w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w1200/2026/06/hi-ai-1200.gif 1200w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w2000/2026/06/hi-ai-1200.gif 2000w"
                    sizes="(max-width: 1200px) 100vw, 1200px"
                    src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/06/hi-ai-1200.gif"
                    alt="&quot;Hi, AI.&quot; in large Chakra Petch type, with the period in Hacks/Hackers green"
                >
            </figure>

        <div class="gh-card-wrapper">
            <header class="gh-card-header">
                <h3 class="gh-card-title">How we made our site more readable for AI agents and how you can too</h3>
            </header>


            <footer class="gh-card-footer">
                <span class="gh-card-author">Burt Herman</span>
                <time class="gh-card-date" datetime="2026-05-27">May 27, 2026</time>
            </footer>
        </div>
    </a>
</article>                        <article class="gh-card post tag-ai-papers-explained">
    <a class="gh-card-link" href="/ai-chatbots-news-intermediaries-stanford-study/">
            <figure class="gh-card-image">
                <img
                    srcset="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w300/2026/05/aichatbotnewsimage.png 300w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/05/aichatbotnewsimage.png 720w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w960/2026/05/aichatbotnewsimage.png 960w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w1200/2026/05/aichatbotnewsimage.png 1200w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w2000/2026/05/aichatbotnewsimage.png 2000w"
                    sizes="(max-width: 1200px) 100vw, 1200px"
                    src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/05/aichatbotnewsimage.png"
                    alt="AI chatbots right about daily news nearly all the time, but fail badly when users slip wrong details into chats"
                >
            </figure>

        <div class="gh-card-wrapper">
            <header class="gh-card-header">
                <h3 class="gh-card-title">AI chatbots right about daily news nearly all the time, but fail badly when users slip wrong details into chats</h3>
            </header>


            <footer class="gh-card-footer">
                <span class="gh-card-author">Hacks/Hackers AI</span>
                <time class="gh-card-date" datetime="2026-05-22">May 22, 2026</time>
            </footer>
        </div>
    </a>
</article>                        <article class="gh-card post tag-ai-x-journalism-summit tag-hash-no-dropcap">
    <a class="gh-card-link" href="/the-room-wasnt-sad-it-was-ready/">
            <figure class="gh-card-image">
                <img
                    srcset="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w300/2026/05/5W9A0940.jpg 300w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/05/5W9A0940.jpg 720w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w960/2026/05/5W9A0940.jpg 960w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w1200/2026/05/5W9A0940.jpg 1200w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w2000/2026/05/5W9A0940.jpg 2000w"
                    sizes="(max-width: 1200px) 100vw, 1200px"
                    src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/05/5W9A0940.jpg"
                    alt="The Room Wasn&#x27;t Sad. It Was Ready."
                >
            </figure>

        <div class="gh-card-wrapper">
            <header class="gh-card-header">
                <h3 class="gh-card-title">The Room Wasn&#x27;t Sad. It Was Ready.</h3>
            </header>


            <footer class="gh-card-footer">
                <span class="gh-card-author">Paul Cheung</span>
                <time class="gh-card-date" datetime="2026-05-19">May 19, 2026</time>
            </footer>
        </div>
    </a>
</article>                        <article class="gh-card post tag-ai-x-journalism-summit tag-hash-no-dropcap featured">
    <a class="gh-card-link" href="/computers-finally-work-the-way-i-dreamed-they-would-but-theyre-keeping-me-up-at-night/">
            <figure class="gh-card-image">
                <img
                    srcset="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w300/2026/05/Sleep.png 300w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/05/Sleep.png 720w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w960/2026/05/Sleep.png 960w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w1200/2026/05/Sleep.png 1200w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w2000/2026/05/Sleep.png 2000w"
                    sizes="(max-width: 1200px) 100vw, 1200px"
                    src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/05/Sleep.png"
                    alt="Computers finally work the way I dreamed they would. But they&#x27;re keeping me up at night."
                >
            </figure>

        <div class="gh-card-wrapper">
            <header class="gh-card-header">
                <h3 class="gh-card-title">Computers finally work the way I dreamed they would. But they&#x27;re keeping me up at night.</h3>
            </header>


            <footer class="gh-card-footer">
                <span class="gh-card-author">Burt Herman</span>
                <time class="gh-card-date" datetime="2026-05-19">May 19, 2026</time>
            </footer>
        </div>
    </a>
</article>                        <article class="gh-card post tag-newsroom-ai-lab">
    <a class="gh-card-link" href="/every-organization-has-a-process-yours-just-isnt-written-down/">
            <figure class="gh-card-image">
                <img
                    srcset="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w300/2026/05/cohort2-feature.png 300w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/05/cohort2-feature.png 720w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w960/2026/05/cohort2-feature.png 960w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w1200/2026/05/cohort2-feature.png 1200w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w2000/2026/05/cohort2-feature.png 2000w"
                    sizes="(max-width: 1200px) 100vw, 1200px"
                    src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/05/cohort2-feature.png"
                    alt="Every organization has a process, yours just isn&#x27;t written down"
                >
            </figure>

        <div class="gh-card-wrapper">
            <header class="gh-card-header">
                <h3 class="gh-card-title">Every organization has a process, yours just isn&#x27;t written down</h3>
            </header>


            <footer class="gh-card-footer">
                <span class="gh-card-author">Paige Moody, Jake Kara</span>
                <time class="gh-card-date" datetime="2026-05-07">May 7, 2026</time>
            </footer>
        </div>
    </a>
</article>                        <article class="gh-card post tag-ai tag-journalism tag-opinion tag-newsrooms">
    <a class="gh-card-link" href="/cms-is-dead-long-live-the-context-management-system/">
            <figure class="gh-card-image">
                <img
                    srcset="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w300/2026/04/notebook-image.png 300w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/04/notebook-image.png 720w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w960/2026/04/notebook-image.png 960w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w1200/2026/04/notebook-image.png 1200w,
                            https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w2000/2026/04/notebook-image.png 2000w"
                    sizes="(max-width: 1200px) 100vw, 1200px"
                    src="https://storage.ghost.io/c/a4/e7/a4e737ce-0487-4330-bd5a-4bb2cffab98a/content/images/size/w720/2026/04/notebook-image.png"
                    alt="A reporter&#x27;s notebook open on a wooden desk in a dim newsroom, with handwritten notes lit by an amber lamp and glowing data nodes rising above it in a network of photos and documents"
                >
            </figure>

        <div class="gh-card-wrapper">
            <header class="gh-card-header">
                <h3 class="gh-card-title">The Content Management System Is Dead. Long Live the Context Management System.</h3>
            </header>


            <footer class="gh-card-footer">
                <span class="gh-card-author">Burt Herman</span>
                <time class="gh-card-date" datetime="2026-04-22">Apr 22, 2026</time>
            </footer>
        </div>
    </a>
</article>            </div>

            <footer class="gh-topic-footer">
                    <a class="gh-topic-link" href="https://www.hackshackers.com/posts/">Show more <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg></a>
            </footer>
        </section>


    </div>
</main>

<script>
(function () {
  var hero = document.querySelector('.hero');
  var svg = hero && hero.querySelector('.hero-field');
  if (!svg) return;
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;

  var slashes = Array.prototype.map.call(svg.querySelectorAll('.hero-slash'), function (el) {
    return { el: el, cx: +el.dataset.cx, cy: +el.dataset.cy, armed: true };
  });

  var R_IN = 150;   // come this close (viewBox units) -> flip
  var R_OUT = 260;  // move out past this -> re-arm

  function toViewBox(clientX, clientY) {
    var pt = svg.createSVGPoint();
    pt.x = clientX; pt.y = clientY;
    var m = svg.getScreenCTM();
    return m ? pt.matrixTransform(m.inverse()) : null;
  }

  function dodge(s) {
    // restart the flip: pass through 'none' + a real reflow (SVG has no offsetWidth)
    s.el.style.animation = 'none';
    s.el.getBoundingClientRect();
    s.el.style.animation = 'heroRotate 950ms ease-in-out';
  }

  hero.addEventListener('pointermove', function (e) {
    if (e.pointerType === 'touch') return;
    var v = toViewBox(e.clientX, e.clientY);
    if (!v) return;
    for (var i = 0; i < slashes.length; i++) {
      var s = slashes[i];
      var d = Math.hypot(s.cx - v.x, s.cy - v.y);
      if (d < R_IN && s.armed) { s.armed = false; dodge(s); }
      else if (d > R_OUT) { s.armed = true; }
    }
  });
  hero.addEventListener('pointerleave', function () {
    for (var i = 0; i < slashes.length; i++) slashes[i].armed = true;
  });
})();
</script>

<script>
(function () {
  var wrap = document.querySelector('[data-hero-photos]');
  if (!wrap) return;
  var tiles = Array.prototype.slice.call(wrap.querySelectorAll('[data-hp-tile]'));
  if (!tiles.length) return;
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;

  var pool = tiles.map(function (t) {
    var img = t.querySelector('img');
    return { src: img.currentSrc || img.src, alt: img.alt || '' };
  });
  Array.prototype.forEach.call(wrap.querySelectorAll('[data-hp-extra]'), function (s) {
    pool.push({ src: s.getAttribute('data-src'), alt: s.getAttribute('data-alt') || '' });
  });
  if (pool.length <= tiles.length) return;   // nothing new to rotate in

  // warm the cache so the wipe never reveals a half-loaded frame
  pool.slice(tiles.length).forEach(function (item) { new Image().src = item.src; });

  var HOLD = 2800, WIPE = 1300;
  var next = tiles.length % pool.length;   // next pool item to reveal
  var turn = 0;                            // which tile flips this round
  var timer = null, busy = false, visible = true;

  function advance() {
    if (busy || document.hidden || !visible) return;
    busy = true;
    var tile = tiles[turn];
    turn = (turn + 1) % tiles.length;
    var item = pool[next];
    next = (next + 1) % pool.length;

    var img = document.createElement('img');
    img.className = 'hp-img hp-enter';
    img.src = item.src;
    img.alt = item.alt;
    var edge = document.createElement('span');
    edge.className = 'hp-edge';
    edge.setAttribute('aria-hidden', 'true');
    tile.appendChild(img);
    tile.appendChild(edge);
    img.addEventListener('animationend', function done() {
      img.removeEventListener('animationend', done);
      var old = tile.querySelector('.hp-img.is-active');
      if (old) old.remove();
      img.classList.remove('hp-enter');
      img.classList.add('is-active');
      edge.remove();
      busy = false;
    });
    // safety: if the animation never fires (e.g. tab throttling), unstick
    setTimeout(function () { busy = false; }, WIPE + 1200);
  }

  function play() { if (!timer) timer = setInterval(advance, HOLD); }
  function stop() { if (timer) { clearInterval(timer); timer = null; } }

  document.addEventListener('visibilitychange', function () {
    document.hidden ? stop() : play();
  });
  if ('IntersectionObserver' in window) {
    new IntersectionObserver(function (entries) {
      entries.forEach(function (e) { visible = e.isIntersecting; e.isIntersecting ? play() : stop(); });
    }, { threshold: 0.2 }).observe(wrap);
  } else {
    play();
  }
})();
</script>


    <footer class="gh-foot gh-outer">
        <div class="gh-foot-inner gh-inner">
                <section class="gh-subscribe">
                    <h3 class="gh-subscribe-title">Subscribe to Hacks/Hackers</h3>
                        <div class="gh-subscribe-description">The Hacks/Hackers newsletter: news, events and jobs at the intersection of journalism and technology.</div>
                    <button class="gh-subscribe-btn gh-btn" data-portal="signup"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
    <path d="M3.33332 3.33334H16.6667C17.5833 3.33334 18.3333 4.08334 18.3333 5.00001V15C18.3333 15.9167 17.5833 16.6667 16.6667 16.6667H3.33332C2.41666 16.6667 1.66666 15.9167 1.66666 15V5.00001C1.66666 4.08334 2.41666 3.33334 3.33332 3.33334Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
    <path d="M18.3333 5L9.99999 10.8333L1.66666 5" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg> Subscribe now</button>
                </section>

            <nav class="gh-foot-menu">
                <ul class="nav">
    <li class="nav-about"><a href="https://www.hackshackers.com/about/">About</a></li>
    <li class="nav-programs"><a href="https://www.hackshackers.com/Programs/">Programs</a></li>
    <li class="nav-events"><a href="https://www.hackshackers.com/Events/">Events</a></li>
    <li class="nav-newsletters"><a href="https://www.hackshackers.com/tag/newsletter/">Newsletters</a></li>
    <li class="nav-support-us"><a href="https://www.hackshackers.com/donate/">Support us</a></li>
    <li class="nav-connect-with-us"><a href="https://www.hackshackers.com/contact/">Connect with Us</a></li>
    <li class="nav-for-ai-agents"><a href="https://www.hackshackers.com/llms.txt">For AI agents</a></li>
</ul>

            </nav>

            <div class="gh-copyright">
                    Hacks/Hackers © 2026. Powered by <a href="https://ghost.org/" target="_blank" rel="noopener">Ghost</a>
            </div>
        </div>
    </footer>

</div>


<script src="https://www.hackshackers.com/assets/built/main.min.js?v=0e87d094ad"></script>

<!-- WebMCP — exposes Hacks/Hackers archive tools to in-browser AI agents.
     Experimental: uses navigator.modelContext (Chrome Early Preview). Feature-
     detected, so it is a no-op in browsers without support. The data tools
     proxy through the hh-mcp Worker (/mcp/web/*) so in-page agent usage is
     tracked in the same Analytics Engine dataset as the MCP server.
     Source of truth: github.com/burtherman/hh-mcp -> web/webmcp.html
     Installed via Ghost Settings -> Code injection -> Site Footer. -->
<script>
(function () {
  var mc = navigator.modelContext;
  if (!mc) return; // not supported in this browser — harmless no-op

  function jsonResult(data) {
    return { content: [{ type: "text", text: JSON.stringify(data) }] };
  }
  function textResult(text) {
    return { content: [{ type: "text", text: text }] };
  }
  function api(path) {
    return fetch(path, { headers: { accept: "application/json" } }).then(function (r) {
      if (!r.ok) throw new Error("hh-mcp " + r.status);
      return r.json();
    });
  }

  // Compact HTML -> Markdown for the current post body. Handles the elements
  // Ghost actually emits; anything unknown falls through to its text content.
  function toMarkdown(node, depth) {
    depth = depth || 0;
    if (node.nodeType === 3) return node.textContent.replace(/\s+/g, " ");
    if (node.nodeType !== 1) return "";
    var tag = node.tagName.toLowerCase();
    var inner = "";
    var kids = node.childNodes;
    for (var i = 0; i < kids.length; i++) inner += toMarkdown(kids[i], depth);
    switch (tag) {
      case "h1": return "\n\n# " + inner.trim() + "\n";
      case "h2": return "\n\n## " + inner.trim() + "\n";
      case "h3": return "\n\n### " + inner.trim() + "\n";
      case "h4": return "\n\n#### " + inner.trim() + "\n";
      case "h5": return "\n\n##### " + inner.trim() + "\n";
      case "h6": return "\n\n###### " + inner.trim() + "\n";
      case "p": return "\n\n" + inner.trim() + "\n";
      case "br": return "  \n";
      case "hr": return "\n\n---\n";
      case "strong": case "b": return "**" + inner.trim() + "**";
      case "em": case "i": return "*" + inner.trim() + "*";
      case "code":
        return node.parentNode && node.parentNode.tagName === "PRE"
          ? inner
          : "`" + inner.trim() + "`";
      case "pre": return "\n\n```\n" + node.textContent.replace(/\n+$/, "") + "\n```\n";
      case "a": return "[" + inner.trim() + "](" + (node.getAttribute("href") || "") + ")";
      case "img": return "![" + (node.getAttribute("alt") || "") + "](" + (node.getAttribute("src") || "") + ")";
      case "blockquote": return "\n\n> " + inner.trim().replace(/\n+/g, "\n> ") + "\n";
      case "ul": case "ol": {
        var items = "";
        var lis = node.children;
        var n = 0;
        for (var j = 0; j < lis.length; j++) {
          if (lis[j].tagName !== "LI") continue;
          n++;
          var li = "";
          for (var k = 0; k < lis[j].childNodes.length; k++) {
            li += toMarkdown(lis[j].childNodes[k], depth + 1);
          }
          var marker = tag === "ol" ? n + ". " : "- ";
          items += "\n" + "  ".repeat(depth) + marker + li.trim();
        }
        return "\n" + items + "\n";
      }
      default: return inner;
    }
  }

  var tools = [
    {
      name: "search_hh_posts",
      title: "Search Hacks/Hackers posts",
      description:
        "Search the Hacks/Hackers article archive by keyword. Returns matching post titles, excerpts and canonical URLs.",
      inputSchema: {
        type: "object",
        properties: {
          query: { type: "string", description: "Search keywords" },
          limit: { type: "integer", description: "Max results (1-20)", default: 5 }
        },
        required: ["query"]
      },
      annotations: { readOnlyHint: true },
      execute: function (input) {
        var q = encodeURIComponent((input && input.query) || "");
        var limit = (input && input.limit) || 5;
        return api("/mcp/web/search?q=" + q + "&limit=" + limit + "&v=1").then(jsonResult);
      }
    },
    {
      name: "list_recent_hh_posts",
      title: "List recent Hacks/Hackers posts",
      description:
        "List the most recent Hacks/Hackers posts, newest first. Optionally filter by tag slug (e.g. 'newsletter'). Returns titles, excerpts and canonical URLs.",
      inputSchema: {
        type: "object",
        properties: {
          limit: { type: "integer", description: "Max results (1-50)", default: 10 },
          tag: { type: "string", description: "Optional tag slug filter" }
        }
      },
      annotations: { readOnlyHint: true },
      execute: function (input) {
        var limit = (input && input.limit) || 10;
        var tag = input && input.tag ? "&tag=" + encodeURIComponent(input.tag) : "";
        return api("/mcp/web/recent?limit=" + limit + tag + "&v=1").then(jsonResult);
      }
    },
    {
      name: "get_page_markdown",
      title: "Get this page as Markdown",
      description:
        "Return the main article content of the current Hacks/Hackers page as clean Markdown.",
      inputSchema: { type: "object", properties: {} },
      annotations: { readOnlyHint: true },
      execute: function () {
        var el = document.querySelector(".gh-content");
        var title = document.querySelector(".gh-article-title");
        var md =
          (title ? "# " + title.textContent.trim() + "\n\n" : "") +
          (el
            ? toMarkdown(el).replace(/\n{3,}/g, "\n\n").trim()
            : "No article content found on this page.");
        try {
          navigator.sendBeacon(
            "/mcp/web/event",
            JSON.stringify({ tool: "get_page_markdown", query: location.pathname })
          );
        } catch (e) {}
        return Promise.resolve(textResult(md));
      }
    }
  ];

  // The API surface is still settling: the W3C spec uses registerTool(), while
  // some Chrome Early Preview builds expose provideContext(). Support whichever
  // the browser actually provides.
  if (typeof mc.registerTool === "function") {
    tools.forEach(function (t) {
      mc.registerTool(t);
    });
  } else if (typeof mc.provideContext === "function") {
    mc.provideContext({ tools: tools });
  }
})();
</script>

<!-- Support Hacks/Hackers — in-post support modules (v3, 2026-07-02 redesign).
     Two placements, post pages only:
       1. .hh-support-cta — one-line italic strip a few paragraphs in (long posts only).
       2. .hh-support-end — mission block at the end, copy left / button right.
     Theme-independent (lives in Code injection so it survives theme swaps).
     Sits AFTER the existing WebMCP script. Do not replace the existing footer. -->
<style>
.post-template .gh-content .hh-support-cta {
  margin: 2.8rem 0;
  padding: 1.2rem 1.6rem;
  border: 1px solid var(--color-border, #e6e4df);
  background: color-mix(in oklab, #008620 3%, #fdfcf8);
}
.post-template .gh-content .hh-support-cta__text {
  margin: 0;
  font-family: var(--font-serif, Fraunces, Georgia, serif);
  font-style: italic;
  font-size: 0.95em;
  line-height: 1.55;
  color: var(--color-secondary-text, #58605e);
}
.post-template .gh-content .hh-support-cta__text a {
  color: var(--color-accent, #008620);
  text-decoration: underline;
}
.post-template .gh-content .hh-support-end {
  margin: 3.2rem 0 0.5rem;
  padding: 2.4rem;
  border: 1px solid var(--color-border, #e6e4df);
  background: color-mix(in oklab, #008620 4%, #fdfcf8);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1.6rem 2.8rem;
}
.post-template .gh-content .hh-support-end__text {
  margin: 0;
  flex: 1 1 32ch;
  font-family: var(--font-sans, sans-serif);
  font-size: 1.6rem;
  line-height: 1.55;
  color: var(--color-primary-text, #29302e);
}
.post-template .gh-content .hh-support-end__btn {
  flex: 0 0 auto;
  display: inline-block;
  padding: 1rem 1.8rem;
  background: var(--color-ink, #0d1312);
  color: var(--color-paper, #fdfcf8);
  font-family: var(--font-sans, sans-serif);
  font-weight: 600;
  font-size: 1.5rem;
  border-radius: 6px;
  text-decoration: none;
  white-space: nowrap;
}
.post-template .gh-content .hh-support-end__btn:hover {
  background: var(--color-accent, #008620);
  color: var(--color-paper, #fdfcf8);
  opacity: 1;
}
</style>
<script>
(function () {
  function isPost() { return document.body.classList.contains("post-template"); }
  function body() { return document.querySelector(".gh-content"); }

  // One-line nudge a few paragraphs in. Long posts only, so it never crowds
  // the end block on a short piece.
  function insertMidCta() {
    if (!isPost()) return;
    var content = body();
    if (!content || content.querySelector(".hh-support-cta")) return;
    var paras = content.querySelectorAll(":scope > p");
    if (paras.length < 6) return;
    var cta = document.createElement("aside");
    cta.className = "hh-support-cta";
    cta.setAttribute("role", "complementary");
    cta.innerHTML =
      '<p class="hh-support-cta__text">Hacks/Hackers is an independent nonprofit: your ' +
      '<a href="https://www.hackshackers.com/donate/">support</a> ' +
      'keeps this work going and our tools open.</p>';
    paras[3].insertAdjacentElement("afterend", cta);
  }

  // Mission block at the very end of the post body: copy left, button right.
  function insertEndCta() {
    if (!isPost()) return;
    var content = body();
    if (!content || content.querySelector(".hh-support-end")) return;
    var end = document.createElement("aside");
    end.className = "hh-support-end";
    end.setAttribute("role", "complementary");
    end.innerHTML =
      '<p class="hh-support-end__text">Hacks/Hackers is an independent nonprofit advancing media innovation. ' +
      'We bring journalists and technologists together, work with technology companies on trusted ' +
      'information and sources, and help newsrooms put AI and new tools to work. What we build ' +
      'is open to everyone. Your support keeps that going.</p>' +
      '<a class="hh-support-end__btn" href="https://www.hackshackers.com/donate/">Support Hacks/Hackers</a>';
    content.appendChild(end);
  }

  function run() { insertMidCta(); insertEndCta(); }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", run);
  } else {
    run();
  }
})();
</script>

<script>
/* HH footer blinking cursor: replace period after year with a cursor span */
(function(){
  function addCursor(){
    var root = document.querySelector('.gh-copyright');
    if (!root || root.dataset.cursorApplied) return;
    var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
    var textNode;
    while ((textNode = walker.nextNode())) {
      var idx = textNode.nodeValue.search(/\d{4}\./);
      if (idx === -1) continue;
      var rest = textNode.splitText(idx + 4);
      rest.nodeValue = rest.nodeValue.replace(/^\./, '');
      var cursor = document.createElement('span');
      cursor.className = 'hh-cursor';
      cursor.setAttribute('aria-hidden', 'true');
      cursor.textContent = '_';
      textNode.parentNode.insertBefore(cursor, rest);
      root.dataset.cursorApplied = '1';
      return;
    }
  }
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', addCursor);
  } else {
    addCursor();
  }
})();
</script>

</body>

</html>
