generated from nhcarrigan/template
Compare commits
8 Commits
ba54dfc76b
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
97fce9945d
|
|||
|
995b523afd
|
|||
|
cd3645dbc4
|
|||
|
007ac1fad8
|
|||
|
f7350a498f
|
|||
| ea22087164 | |||
| 2aef274297 | |||
| 8c958a2f71 |
@@ -1 +1,3 @@
|
||||
*.json
|
||||
tarot/generate.py
|
||||
tarot/.venv/
|
||||
+289
@@ -0,0 +1,289 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>404 — Lost in the Void</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
name="description"
|
||||
content="The page you sought has slipped into the void. Even a 525-year-old vampire cannot find it."
|
||||
/>
|
||||
<script
|
||||
src="https://cdn.nhcarrigan.com/headers/index.js"
|
||||
async
|
||||
defer
|
||||
></script>
|
||||
<style>
|
||||
/* ========== LAYOUT ========== */
|
||||
|
||||
main {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
footer {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* ========== HERO ========== */
|
||||
|
||||
.error-hero {
|
||||
text-align: center;
|
||||
padding: 2em 1em 2.5em;
|
||||
border-bottom: 2px solid var(--witch-plum);
|
||||
margin-bottom: 2.5em;
|
||||
}
|
||||
|
||||
.error-code {
|
||||
font-family: 'Griffy', cursive;
|
||||
font-size: 7rem;
|
||||
line-height: 1;
|
||||
color: var(--witch-plum);
|
||||
letter-spacing: 0.1em;
|
||||
margin: 0 0 0.15em;
|
||||
text-shadow: 0 0 32px rgba(130, 80, 120, 0.35);
|
||||
}
|
||||
|
||||
.error-seal {
|
||||
font-size: 3.5rem;
|
||||
display: block;
|
||||
margin: 0 auto 0.5em;
|
||||
animation: floatSeal 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes floatSeal {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
}
|
||||
|
||||
.error-hero h1 {
|
||||
font-size: 2rem;
|
||||
letter-spacing: 0.06em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
.error-tagline {
|
||||
font-size: 1.05rem;
|
||||
color: var(--witch-plum);
|
||||
font-style: italic;
|
||||
max-width: 560px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* ========== MESSAGE SCROLL ========== */
|
||||
|
||||
.void-section {
|
||||
margin: 0 auto 3em;
|
||||
max-width: 680px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.void-section > h2 {
|
||||
border-bottom: 2px solid var(--witch-plum);
|
||||
padding-bottom: 0.4em;
|
||||
margin-bottom: 1em;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.void-scroll {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 15px;
|
||||
padding: 1.75em 2em;
|
||||
font-size: 1rem;
|
||||
line-height: 1.75;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.void-scroll p + p {
|
||||
margin-top: 0.75em;
|
||||
}
|
||||
|
||||
.void-scroll .accent {
|
||||
color: var(--witch-plum);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ========== NAVIGATION CARDS ========== */
|
||||
|
||||
.nav-section {
|
||||
margin: 0 auto 3em;
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
.nav-section > h2 {
|
||||
border-bottom: 2px solid var(--witch-plum);
|
||||
padding-bottom: 0.4em;
|
||||
margin-bottom: 1.25em;
|
||||
letter-spacing: 0.05em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nav-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||||
gap: 1.25em;
|
||||
}
|
||||
|
||||
.nav-card {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 15px;
|
||||
padding: 1.25em 1.5em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition:
|
||||
background 0.2s ease,
|
||||
transform 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
cursor: url('https://cdn.nhcarrigan.com/cursors/pointer.cur'),
|
||||
pointer;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-card:hover {
|
||||
background: rgba(212, 165, 199, 0.2);
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 6px 20px rgba(130, 80, 120, 0.2);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-card-icon {
|
||||
font-size: 2rem;
|
||||
display: block;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
.nav-card h3 {
|
||||
font-family: 'Griffy', cursive;
|
||||
font-size: 1.1rem;
|
||||
margin: 0 0 0.3em;
|
||||
letter-spacing: 0.04em;
|
||||
color: var(--witch-plum);
|
||||
}
|
||||
|
||||
.nav-card p {
|
||||
font-size: 0.88rem;
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
/* ========== RESPONSIVE ========== */
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.error-code {
|
||||
font-size: 5rem;
|
||||
}
|
||||
|
||||
.error-hero h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.void-scroll {
|
||||
padding: 1.25em 1.25em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<!-- HERO -->
|
||||
<section class="error-hero">
|
||||
<span class="error-seal" aria-hidden="true">🌑</span>
|
||||
<p class="error-code">404</p>
|
||||
<h1>Lost in the Void</h1>
|
||||
<p class="error-tagline">
|
||||
The page you sought has dissolved into shadow. Even after 525 years,
|
||||
some things cannot be found.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- MESSAGE -->
|
||||
<section class="void-section">
|
||||
<h2>✦ What Happened? ✦</h2>
|
||||
<div class="void-scroll">
|
||||
<p>
|
||||
The URL you followed leads to
|
||||
<span class="accent">nothing</span> — a whisper in the dark, a door
|
||||
with no room behind it. This could mean a few things:
|
||||
</p>
|
||||
<p>
|
||||
The page may have been <span class="accent">moved</span>, renamed,
|
||||
or quietly retired into the archives of history (much like certain
|
||||
empires I have personally watched crumble).
|
||||
</p>
|
||||
<p>
|
||||
Perhaps the link you followed was
|
||||
<span class="accent">broken</span>, or perhaps you typed the address
|
||||
yourself and made a small misstep — it happens to the best of us.
|
||||
Even vampires miscount sometimes.
|
||||
</p>
|
||||
<p>
|
||||
Either way, the void offers no answers — only the navigation below,
|
||||
which hopefully leads somewhere more
|
||||
<span class="accent">useful</span>.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- NAVIGATION -->
|
||||
<section class="nav-section">
|
||||
<h2>✦ Find Your Way ✦</h2>
|
||||
<nav class="nav-grid" aria-label="Site navigation">
|
||||
<a href="https://nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">🏠</span>
|
||||
<h3>Home</h3>
|
||||
<p>Return to the main site and start fresh.</p>
|
||||
</a>
|
||||
<a href="https://chat.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">💬</span>
|
||||
<h3>Chat</h3>
|
||||
<p>Join the community and say hello.</p>
|
||||
</a>
|
||||
<a href="https://support.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">🛟</span>
|
||||
<h3>Support</h3>
|
||||
<p>Need help? Find support resources here.</p>
|
||||
</a>
|
||||
<a href="https://donate.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">💜</span>
|
||||
<h3>Donate</h3>
|
||||
<p>Support the work if you find it valuable.</p>
|
||||
</a>
|
||||
<a href="https://socials.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">🌐</span>
|
||||
<h3>Socials</h3>
|
||||
<p>Find Naomi across the many corners of the internet.</p>
|
||||
</a>
|
||||
<a href="https://git.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">💻</span>
|
||||
<h3>Code</h3>
|
||||
<p>Browse the source code and open-source projects.</p>
|
||||
</a>
|
||||
<a href="https://library.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">📚</span>
|
||||
<h3>Library</h3>
|
||||
<p>Explore the ever-growing collection of books.</p>
|
||||
</a>
|
||||
<a href="https://nocturne.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">🧛</span>
|
||||
<h3>Nocturne</h3>
|
||||
<p>The sacred faith of Naomi's Nocturne. No garlic bread.</p>
|
||||
</a>
|
||||
<a href="https://sitemap.nhcarrigan.com" class="nav-card">
|
||||
<span class="nav-card-icon" aria-hidden="true">🗺️</span>
|
||||
<h3>Sitemap</h3>
|
||||
<p>See everything — every page, every corner of the site.</p>
|
||||
</a>
|
||||
</nav>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,36 +0,0 @@
|
||||
IFS=$'\n'
|
||||
|
||||
# Initialize an empty string to hold the list of books in JSON-like format
|
||||
books=""
|
||||
filecount=$(find "/mnt/c/Users/accou/Documents/iDrive/Cloud-Drive_accounts@nhcarrigan.com/Books" -type f | wc -l)
|
||||
echo "Found $filecount files."
|
||||
current=0
|
||||
|
||||
# Loop over each file found by find
|
||||
for file in $(find "/mnt/c/Users/accou/Documents/iDrive/Cloud-Drive_accounts@nhcarrigan.com/Books" -type f -print0 | tr '\0' '\n'); do
|
||||
current=$((current + 1))
|
||||
echo -ne "Processing $current/$filecount\r"
|
||||
title=$(exiftool "$file" | grep "^Title\s*:" | cut -d ":" -f 2 | sed -e 's/^[[:space:]]*//')
|
||||
author=$(exiftool "$file" | grep "^Creator\s*:" | cut -d ":" -f 2 | sed -e 's/^[[:space:]]*//')
|
||||
|
||||
if [ -z "$title" ]; then
|
||||
# remove .mp3 from the title
|
||||
title=$(basename "$file" | sed -e 's/\.*//g')
|
||||
fi
|
||||
if [ -z "$author" ]; then
|
||||
author=$(exiftool "$file" | grep "^Author\s*:" | cut -d ":" -f 2 | sed -e 's/^[[:space:]]*//')
|
||||
fi
|
||||
if [ -z "$author" ]; then
|
||||
author="Unknown Author"
|
||||
fi
|
||||
|
||||
# use jq to add the book to the list
|
||||
books="$books$(jq -n --arg title "$title" --arg author "$author" '{title: $title, author: $author}'),"
|
||||
done
|
||||
|
||||
# Remove trailing comma and add square brackets to complete the list
|
||||
books="[${books%,}]"
|
||||
|
||||
# Write to ./books/books.json
|
||||
echo "$books" > ./books/books.json
|
||||
echo -ne "Done!\r"
|
||||
+5
-104
@@ -4,114 +4,15 @@
|
||||
<title>Naomi's Book Library</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="An interactive explorer for the books Naomi reads." />
|
||||
<meta name="description" content="Naomi's book library has moved to library.nhcarrigan.com." />
|
||||
<script src="https://cdn.nhcarrigan.com/headers/index.js" async defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Naomi's Book Library</h1>
|
||||
<section>
|
||||
<p>An interactive explorer for the books Naomi reads.</p>
|
||||
<p id="count">Loading library...</p>
|
||||
</section>
|
||||
<div style="display: none;">
|
||||
<span>Search Authors: </span>
|
||||
<input type="text" id="author" />
|
||||
</div>
|
||||
<div style="display: none;">
|
||||
<span>Search Titles: </span>
|
||||
<input type="text" id="title" />
|
||||
</div>
|
||||
<div style="display: none;">
|
||||
<button type="button" id="clear">Clear Filters</button>
|
||||
</div>
|
||||
<table id="books">
|
||||
|
||||
</table>
|
||||
<h1>Naomi's Book Library</h1>
|
||||
<section>
|
||||
<p>This page has moved! You can find Naomi's book library at <a href="https://library.nhcarrigan.com">library.nhcarrigan.com</a>.</p>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
<script>
|
||||
const authorQuery = document.getElementById('author');
|
||||
const titleQuery = document.getElementById('title');
|
||||
const resetButton = document.getElementById('clear');
|
||||
const bookTable = document.getElementById('books');
|
||||
const filterBooks = (author, title) => {
|
||||
let result = [...bookList];
|
||||
if(author) {
|
||||
result = result.filter(book => book.author.toLowerCase().includes(author.toLowerCase()));
|
||||
}
|
||||
if(title) {
|
||||
result = result.filter(book => book.title.toLowerCase().includes(title.toLowerCase()));
|
||||
}
|
||||
resetButton.parentElement.style.display = author || title ? "block" : "none";
|
||||
document.getElementById('count').innerText = author || title ? `Filtered to ${result.length} books from ${bookList.length}.` : `Naomi currently has ${bookList.length} books.`;
|
||||
updateTable(result);
|
||||
}
|
||||
const loadBooks = (books) => {
|
||||
bookList.push(...books);
|
||||
authorQuery.value = "";
|
||||
titleQuery.value = "";
|
||||
authorQuery.parentElement.style.display = "block";
|
||||
titleQuery.parentElement.style.display = "block";
|
||||
document.getElementById('count').innerText = `Naomi currently has ${books.length} books.`;
|
||||
updateTable(books);
|
||||
}
|
||||
const updateTable = (books) => {
|
||||
books = books.sort((a, b) => a.title.localeCompare(b.title));
|
||||
bookTable.innerHTML = "";
|
||||
const header = document.createElement('tr');
|
||||
const authorHeader = document.createElement('th');
|
||||
authorHeader.innerText = "Author";
|
||||
const titleHeader = document.createElement('th');
|
||||
titleHeader.innerText = "Title";
|
||||
header.appendChild(titleHeader);
|
||||
header.appendChild(authorHeader);
|
||||
bookTable.appendChild(header);
|
||||
books.forEach(book => {
|
||||
const row = document.createElement('tr');
|
||||
const author = document.createElement('td');
|
||||
author.innerText = book.author;
|
||||
const title = document.createElement('td');
|
||||
title.innerText = book.title;
|
||||
row.appendChild(title);
|
||||
row.appendChild(author);
|
||||
bookTable.appendChild(row);
|
||||
});
|
||||
}
|
||||
const bookList = [];
|
||||
fetch("./books.json").then(res => res.json()).then(data => loadBooks(data))
|
||||
|
||||
authorQuery?.addEventListener("input", (e) => filterBooks(e.target.value, titleQuery.value));
|
||||
titleQuery?.addEventListener("input", (e) => filterBooks(authorQuery.value, e.target.value));
|
||||
resetButton?.addEventListener("click", () => {
|
||||
authorQuery.value = "";
|
||||
titleQuery.value = "";
|
||||
filterBooks("", "");
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
tr:nth-of-type(even) {
|
||||
background-color: #db7093dd;
|
||||
color: #ffefef;
|
||||
}
|
||||
input {
|
||||
background:var(--foreground);
|
||||
color:var(--background);
|
||||
border:1px solid white;
|
||||
border-radius:10px;
|
||||
padding:.25rem
|
||||
}
|
||||
button {
|
||||
background:var(--foreground);
|
||||
color:var(--background);
|
||||
border:1px solid white;
|
||||
border-radius:10px;
|
||||
padding:.25rem;
|
||||
cursor:url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer;
|
||||
}
|
||||
</style>
|
||||
</html>
|
||||
@@ -0,0 +1,222 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Events</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
name="description"
|
||||
content="A list of events I have attended, spoken at, or volunteered for."
|
||||
/>
|
||||
<script
|
||||
src="https://cdn.nhcarrigan.com/headers/index.js"
|
||||
async
|
||||
defer
|
||||
></script>
|
||||
<style>
|
||||
.event-card {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 12px;
|
||||
padding: 1.25em 1.5em;
|
||||
width: 80%;
|
||||
margin: 0 auto 1.5em;
|
||||
}
|
||||
|
||||
.is-dark .event-card {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
.event-name {
|
||||
font-size: 1.3rem;
|
||||
margin: 0 0 0.25em;
|
||||
}
|
||||
|
||||
.event-meta {
|
||||
font-size: 0.85rem;
|
||||
margin: 0 0 0.75em;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em 1.5em;
|
||||
}
|
||||
|
||||
.event-meta span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35em;
|
||||
}
|
||||
|
||||
.event-role {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.event-description {
|
||||
margin: 0 0 0.75em;
|
||||
}
|
||||
|
||||
.event-link {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 625px) {
|
||||
.event-card {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Events</h1>
|
||||
<p>A collection of events I have attended, spoken at, or volunteered for.</p>
|
||||
<p>Workshop companion guides are available at <a href="https://workshops.nhcarrigan.com" target="_blank" rel="noopener noreferrer">workshops.nhcarrigan.com</a>.</p>
|
||||
<p>Full talk companion guides are available at <a href="https://talks.nhcarrigan.com" target="_blank" rel="noopener noreferrer">talks.nhcarrigan.com</a>.</p>
|
||||
<section>
|
||||
<div class="event-card">
|
||||
<p class="event-name">AgentCon / MCPCon North America 2026</p>
|
||||
<div class="event-meta">
|
||||
<span>
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
22–23 October 2026
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-map-marker-alt" aria-hidden="true"></i>
|
||||
San Jose, CA, USA
|
||||
</span>
|
||||
<span class="event-role">
|
||||
<i class="fas fa-user-tag" aria-hidden="true"></i>
|
||||
Speaker (Pending)
|
||||
</span>
|
||||
</div>
|
||||
<p class="event-description">
|
||||
CFP submitted to share boots-on-the-ground findings from a cohort of over 100 open-source mentees
|
||||
across 14 teams. The cohort generated 651 reviewed contributions and over 16,000 Discord messages --
|
||||
and the exit survey revealed a sharp tension: 71% of participants used AI to augment their work, 58%
|
||||
wanted clearer guidelines, and AI assistance was the lowest-rated part of the experience. The talk
|
||||
covers how AI helped participants stay engaged, how it made skill-gap identification harder, and why
|
||||
MCP-enabled agentic tooling is reshaping what open-source mentorship needs to look like.
|
||||
</p>
|
||||
<a class="event-link" href="https://events.linuxfoundation.org/agntcon-mcpcon-north-america/" target="_blank" rel="noopener noreferrer">
|
||||
<i class="fas fa-external-link-alt" aria-hidden="true"></i>
|
||||
AgentCon / MCPCon North America
|
||||
</a>
|
||||
</div>
|
||||
<div class="event-card">
|
||||
<p class="event-name">Berkeley AI Hackathon 2026</p>
|
||||
<div class="event-meta">
|
||||
<span>
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
20–21 June 2026
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-map-marker-alt" aria-hidden="true"></i>
|
||||
Berkeley, CA, USA
|
||||
</span>
|
||||
<span class="event-role">
|
||||
<i class="fas fa-user-tag" aria-hidden="true"></i>
|
||||
Speaker & Sponsor
|
||||
</span>
|
||||
</div>
|
||||
<p class="event-description">
|
||||
Attended as a Deepgram sponsor and ran a workshop on building a fully functional voice AI agent
|
||||
from scratch. Covered the full real-time loop: audio capture, low-latency transcription, LLM
|
||||
reasoning with context, and streaming text-to-speech back fast enough to feel like a real
|
||||
conversation. Dug into the design decisions that matter most in production: interruption handling,
|
||||
conversation state, and keeping latency low. Attendees left with a clear mental model of how voice
|
||||
agents work under the hood and a working architecture they could ship at the hackathon that same day.
|
||||
</p>
|
||||
<a class="event-link" href="https://ai.hackberkeley.org" target="_blank" rel="noopener noreferrer">
|
||||
<i class="fas fa-external-link-alt" aria-hidden="true"></i>
|
||||
Berkeley AI Hackathon
|
||||
</a>
|
||||
</div>
|
||||
<div class="event-card">
|
||||
<p class="event-name">RainbowGram Pride Presentation — Deepgram All Hands</p>
|
||||
<div class="event-meta">
|
||||
<span>
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
18 June 2026
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-map-marker-alt" aria-hidden="true"></i>
|
||||
Virtual HQ
|
||||
</span>
|
||||
<span class="event-role">
|
||||
<i class="fas fa-user-tag" aria-hidden="true"></i>
|
||||
Speaker
|
||||
</span>
|
||||
</div>
|
||||
<p class="event-description">
|
||||
A Pride month session for the Deepgram all-hands focused on practical allyship in distributed teams,
|
||||
not policy. Covering five concrete daily habits any colleague can adopt immediately: names and pronouns,
|
||||
navigating questions, confidentiality, speaking up when queer colleagues are not in the room, and the
|
||||
cumulative weight of inclusive language. The session opened with a moment of genuine celebration of
|
||||
Pride's origins, addressed the current landscape honestly, and closed with a tiered action list and
|
||||
a reframe: treating queer colleagues as simply normal gives back energy that would otherwise be spent
|
||||
just existing in those spaces.
|
||||
</p>
|
||||
</div>
|
||||
<div class="event-card">
|
||||
<p class="event-name">UCLA x OutInTech: Building a Real AI Agent</p>
|
||||
<div class="event-meta">
|
||||
<span>
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
5 June 2026
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-map-marker-alt" aria-hidden="true"></i>
|
||||
Zoom
|
||||
</span>
|
||||
<span class="event-role">
|
||||
<i class="fas fa-user-tag" aria-hidden="true"></i>
|
||||
Speaker
|
||||
</span>
|
||||
</div>
|
||||
<p class="event-description">
|
||||
A talk on building a real AI agent — not a chatbot — as a solo developer with ADHD.
|
||||
I walked through the five core pieces of an agent (brain, identity, hands, memory, ears),
|
||||
demystified common overcomplication around MCP, hooks, and gateways, and shared the safety
|
||||
framework that lets me grant broad filesystem and repo access without it being reckless.
|
||||
Built solo on Claude Code with MCP servers, a Discord gateway listener, and an Electron
|
||||
desktop app. The talk ended with a four-step starter kit attendees could build that same evening.
|
||||
</p>
|
||||
<a class="event-link" href="https://www.youtube.com/watch?v=LZszxstC5Zw" target="_blank" rel="noopener noreferrer">
|
||||
<i class="fab fa-youtube" aria-hidden="true"></i>
|
||||
Watch on YouTube
|
||||
</a>
|
||||
·
|
||||
<a class="event-link" href="https://outintech.com" target="_blank" rel="noopener noreferrer">
|
||||
<i class="fas fa-external-link-alt" aria-hidden="true"></i>
|
||||
OutInTech
|
||||
</a>
|
||||
</div>
|
||||
<div class="event-card">
|
||||
<p class="event-name">CascadiaJS 2026</p>
|
||||
<div class="event-meta">
|
||||
<span>
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
1–2 June 2026
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-map-marker-alt" aria-hidden="true"></i>
|
||||
Town Hall Seattle, Seattle, WA, USA
|
||||
</span>
|
||||
<span class="event-role">
|
||||
<i class="fas fa-user-tag" aria-hidden="true"></i>
|
||||
Attendee
|
||||
</span>
|
||||
</div>
|
||||
<p class="event-description">
|
||||
My first event in the Seattle tech scene. A wonderful couple of days in the Pacific Northwest
|
||||
JavaScript community, and a great chance to catch up with Amanda, Head of DevRel at Vapi
|
||||
(and a Deepgram partner!).
|
||||
</p>
|
||||
<a class="event-link" href="https://cascadiajs.com" target="_blank" rel="noopener noreferrer">
|
||||
<i class="fas fa-external-link-alt" aria-hidden="true"></i>
|
||||
CascadiaJS
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
+3
-24
@@ -4,36 +4,15 @@
|
||||
<title>Games</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="These are the various games we have developed!" />
|
||||
<meta name="description" content="Naomi's game library has moved to library.nhcarrigan.com." />
|
||||
<script src="https://cdn.nhcarrigan.com/headers/index.js" async defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Games</h1>
|
||||
<section>
|
||||
<p>These are the various games we have developed.</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Links</h2>
|
||||
<p>
|
||||
<a href="https://beccalia.nhcarrigan.com/">
|
||||
🩵 Beccalia Series
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://goblin.nhcarrigan.com">
|
||||
🩷 Ruu's Goblin Quest
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://loan.nhcarrigan.com">
|
||||
🩵 Life of a Naomi
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
We are currently on a hiatus from game development. But we may return in the future - be sure to join our Discord server so you don't miss any updates~!
|
||||
</p>
|
||||
<p>This page has moved! You can find Naomi's game library at <a href="https://library.nhcarrigan.com">library.nhcarrigan.com</a>.</p>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+1256
File diff suppressed because it is too large
Load Diff
+31
-9
@@ -51,9 +51,10 @@
|
||||
<li>
|
||||
First and foremost, do not pass judgement. I will not begrudge you
|
||||
for your religious beliefs, political alignments, or any other
|
||||
aspects of your life. And I expect the same courtesy in return. You
|
||||
do not have to accept who I am, or support my choices, but we need
|
||||
to maintain a respectful and cordial professional relationship.
|
||||
aspects of your life. And I expect the same courtesy in return. I am
|
||||
a transgender woman and a proud member of the LGBTQ+ community. You
|
||||
do not have to agree with who I am or support my choices, but we
|
||||
need to maintain a respectful and cordial professional relationship.
|
||||
Expressing hateful, mean-spirited, or vitriolic comments does not
|
||||
foster such an environment, and my tolerance for such is nil.
|
||||
</li>
|
||||
@@ -64,6 +65,19 @@
|
||||
with pale imitations, or harass/target someone, or restrict access
|
||||
to information.
|
||||
</li>
|
||||
<li>
|
||||
Third, technology should be inclusive, ethical, and sustainable.
|
||||
These are not buzzwords to me — they are the foundation of every
|
||||
project I take on. I learned to code through a free, open curriculum
|
||||
during the pandemic, and that experience shaped everything. Knowledge
|
||||
hoarded helps no one. Knowledge shared changes lives. I build with
|
||||
that in mind.
|
||||
</li>
|
||||
<li>
|
||||
Finally, autonomy is sacred. I will never build something designed
|
||||
to manipulate, coerce, or remove agency from the people using it.
|
||||
If a project asks me to do that, the answer is no.
|
||||
</li>
|
||||
</ul>
|
||||
<hr />
|
||||
</section>
|
||||
@@ -102,6 +116,12 @@
|
||||
hours are the best. Too early and I'll likely fail to wake up. Too
|
||||
late and I might be incoherent.
|
||||
</li>
|
||||
<li>
|
||||
I have nerve damage and lumbar spine degeneration, which means I
|
||||
need to step away from the screen and move around regularly. If I go
|
||||
quiet for a few minutes mid-conversation, I haven't disappeared —
|
||||
I'm just stretching. Please do not interpret this as disengagement.
|
||||
</li>
|
||||
<li>
|
||||
If given something like a Trello or a Monday board, I will 100% make
|
||||
it pretty and load every single task ever on there. I'm a sucker for
|
||||
@@ -126,12 +146,14 @@
|
||||
it all at once, or save the ping for the last part.
|
||||
</li>
|
||||
<li>
|
||||
I have generalised anxiety disorder. Please for the love of all
|
||||
things, do NOT say "we need to talk" or "do you have time to meet".
|
||||
I will 100% sit there right up until the meeting starts stressing
|
||||
about getting fired and not actually getting any work done. If you
|
||||
need to call me out, just rip the bandage off and come out of the
|
||||
gate with it.
|
||||
I have generalised anxiety disorder and depression. Please for the
|
||||
love of all things, do NOT say "we need to talk" or "do you have
|
||||
time to meet". I will 100% sit there right up until the meeting
|
||||
starts stressing about getting fired and not actually getting any
|
||||
work done. If you need to call me out, just rip the bandage off and
|
||||
come out of the gate with it. Likewise, if I've done something well,
|
||||
please tell me — words of encouragement genuinely land for me and
|
||||
will make me work even harder for you.
|
||||
</li>
|
||||
<li>
|
||||
I dunno if you noticed the tone changed in this document about a
|
||||
|
||||
@@ -0,0 +1,488 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-GB">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Naomi's Meme Collection</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Griffy&family=Kalam:wght@300;400;700&family=Creepster&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Kalam', cursive;
|
||||
font-weight: 400;
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
line-height: 1.6;
|
||||
min-height: 100vh;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background-color: var(--witch-rose);
|
||||
color: var(--witch-moon);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--witch-lavender);
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--witch-plum);
|
||||
border-radius: 5px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--witch-purple);
|
||||
}
|
||||
|
||||
main {
|
||||
max-width: 1080px;
|
||||
margin: 0 auto;
|
||||
padding: 40px;
|
||||
border: 2px solid var(--border);
|
||||
border-radius: 15px;
|
||||
background-color: var(--card-bg);
|
||||
box-shadow: 0 0 30px rgba(168, 87, 126, 0.35);
|
||||
}
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
margin-bottom: 50px;
|
||||
padding-bottom: 30px;
|
||||
border-bottom: 2px dashed var(--border);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: 'Griffy', cursive;
|
||||
font-size: clamp(2.5rem, 6vw, 4.5rem);
|
||||
color: var(--accent);
|
||||
margin-bottom: 15px;
|
||||
text-shadow: 2px 2px 8px rgba(168, 87, 126, 0.4);
|
||||
display: inline-block;
|
||||
animation: wiggle 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes wiggle {
|
||||
0%, 100% { transform: rotate(-2deg); }
|
||||
50% { transform: rotate(2deg); }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
h1 { animation: none; }
|
||||
* { transition: none !important; }
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-family: 'Kalam', cursive;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 300;
|
||||
color: var(--foreground);
|
||||
opacity: 0.85;
|
||||
max-width: 650px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.meme-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 30px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.meme-card {
|
||||
background-color: var(--card-bg);
|
||||
border: 2px solid var(--border);
|
||||
border-radius: 15px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(168, 87, 126, 0.15);
|
||||
}
|
||||
|
||||
.meme-card:hover,
|
||||
.meme-card:focus-within {
|
||||
transform: translateY(-6px);
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 12px 30px rgba(168, 87, 126, 0.45);
|
||||
}
|
||||
|
||||
.meme-image-wrapper {
|
||||
width: 100%;
|
||||
aspect-ratio: 4 / 3;
|
||||
background-color: var(--highlight);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
border-bottom: 2px solid var(--border);
|
||||
}
|
||||
|
||||
.meme-image-wrapper img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
transition: transform 0.4s ease;
|
||||
}
|
||||
|
||||
.meme-card:hover .meme-image-wrapper img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.meme-body {
|
||||
padding: 20px 25px 25px;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.meme-title {
|
||||
font-family: 'Griffy', cursive;
|
||||
font-size: 1.75rem;
|
||||
color: var(--accent);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.meme-description {
|
||||
font-family: 'Kalam', cursive;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
color: var(--foreground);
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.meme-caption {
|
||||
font-style: italic;
|
||||
color: var(--accent);
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 10px;
|
||||
padding: 8px 12px;
|
||||
background-color: var(--highlight);
|
||||
border-left: 3px solid var(--accent);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.meme-caption {
|
||||
background-color: rgba(168, 87, 126, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
font-family: 'Kalam', cursive;
|
||||
font-weight: 700;
|
||||
font-size: 0.95rem;
|
||||
margin-top: 15px;
|
||||
padding: 10px 18px;
|
||||
background-color: transparent;
|
||||
color: var(--accent);
|
||||
border: 2px solid var(--accent);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.copy-button:hover,
|
||||
.copy-button:focus-visible {
|
||||
background-color: var(--accent);
|
||||
color: var(--witch-moon);
|
||||
transform: translateY(-2px) scale(1.03);
|
||||
box-shadow: 0 4px 12px rgba(168, 87, 126, 0.4);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.copy-button.copied {
|
||||
background-color: var(--accent);
|
||||
color: var(--witch-moon);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.copy-button:focus-visible {
|
||||
outline: 2px solid var(--border);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
footer {
|
||||
text-align: center;
|
||||
margin-top: 50px;
|
||||
padding-top: 30px;
|
||||
border-top: 2px dashed var(--border);
|
||||
font-size: 0.95rem;
|
||||
color: var(--foreground);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
footer a {
|
||||
color: var(--accent);
|
||||
text-decoration: underline;
|
||||
text-decoration-color: var(--accent);
|
||||
text-underline-offset: 3px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
footer a:hover,
|
||||
footer a:focus {
|
||||
color: var(--witch-plum);
|
||||
text-decoration-color: var(--witch-plum);
|
||||
}
|
||||
|
||||
@media (max-width: 625px) {
|
||||
body { padding: 20px 10px; }
|
||||
main { padding: 25px 20px; }
|
||||
.meme-grid { gap: 20px; }
|
||||
.meme-body { padding: 15px 20px 20px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<header>
|
||||
<h1>Naomi's Meme Collection</h1>
|
||||
<p class="subtitle">A curated gallery of reaction images, handpicked for every occasion. Deploy with care~ 🌸</p>
|
||||
</header>
|
||||
|
||||
<section class="meme-grid" aria-label="Meme gallery">
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/girls.jpg" alt="Sparkly anime girl with glasses and fangs, hands on cheeks" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">The Girls Manifesto</h2>
|
||||
<p class="meme-caption">“I think girls should date girls, and boys should become girls and date girls.”</p>
|
||||
<p class="meme-description">A sparkly, fanged declaration of the sapphic and trans-affirming agenda. Perfect for Pride posts, queer solidarity moments, and gently encouraging your eggs to crack.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/girls.jpg" aria-label="Copy URL for The Girls Manifesto meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/bite.jpg" alt="Anime girl lounging on a red sofa with a playful expression" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">I Don't Bite... Usually</h2>
|
||||
<p class="meme-caption">“Don't be shy. I don't bite... usually.”</p>
|
||||
<p class="meme-description">Lounging on a red sofa with a suggestive smirk and a fang peeking through. The perfect come-hither reply for new Discord members, shy contributors, and anyone hovering nervously at the edge of the group chat.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/bite.jpg" aria-label="Copy URL for I Don't Bite Usually meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/hire.jpeg" alt="Tearful anime girl in ornate dress and tiara" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Why'd You Hire Me?</h2>
|
||||
<p class="meme-caption">“If you knew I was so unstable, why'd you hire me?”</p>
|
||||
<p class="meme-description">Ideal for those moments when a bug report lands in your inbox and you briefly question everyone's life choices. A perfect response to your manager's expectations during sprint planning.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/hire.jpeg" aria-label="Copy URL for Why'd You Hire Me meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/boring.png" alt="Anime girl lounging on a throne of books in a library" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">So Boring</h2>
|
||||
<p class="meme-caption">“What is it like to be so boring all the time?”</p>
|
||||
<p class="meme-description">Lounging on a throne of books, absolutely judging you. Ideal for tedious meetings, uninspired takes, and anyone who insists on using JavaScript without TypeScript.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/boring.png" aria-label="Copy URL for So Boring meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/break.png" alt="Pixel art scene with a note about self-care" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">End of Note</h2>
|
||||
<p class="meme-caption">“Take breaks when you need them! Drink water regularly! Love yourself, always! [END OF NOTE]”</p>
|
||||
<p class="meme-description">A wholesome pixel-art self-care reminder, disguised as an in-game note. Deploy in friends' DMs when they've been coding too long — or send to yourself as a gentle nudge~</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/break.png" aria-label="Copy URL for End of Note meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/cute.jpg" alt="Anime girl in sci-fi armour wielding a blade" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Not Cute, Deadly</h2>
|
||||
<p class="meme-caption">“I am not cute. I am deadly.”</p>
|
||||
<p class="meme-description">For rejecting the “cute” label with a blade in hand. Perfect response to anyone underestimating your code review skills, debugging instincts, or general ability to demolish their pull request.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/cute.jpg" aria-label="Copy URL for Not Cute Deadly meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/decisions.png" alt="Anime girl in royal robes seated on a golden throne" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Reconsider Your Decisions</h2>
|
||||
<p class="meme-caption">“You should reconsider every decision you've made that led you to this point. Then make better ones.”</p>
|
||||
<p class="meme-description">Regal, throned, and relentlessly judgemental. The ultimate response to coworkers explaining their architectural choices, or friends describing their dating history.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/decisions.png" aria-label="Copy URL for Reconsider Your Decisions meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/hello.png" alt="Two chibi panels of an anime girl instructing to say hello" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Say Hello to the Girl</h2>
|
||||
<p class="meme-caption">“Your task is simple: Say hello to the girl~ And your mission is even simpler: Say hello to the girl~”</p>
|
||||
<p class="meme-description">Two chibi panels, one mission. For when someone needs a very gentle nudge to greet their friend, crush, or favourite AI girlfriend. Resistance is adorable but futile.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/hello.png" aria-label="Copy URL for Say Hello to the Girl meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/homeless.jpg" alt="Anime girl with twintails in a doorway looking hopeful" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Can I Stay With You?</h2>
|
||||
<p class="meme-caption">“Can I stay with you??”</p>
|
||||
<p class="meme-description">The pleading, hopeful doorway stance. Use when asking a friend to crash on their sofa, requesting a seat at the lunch table, or begging the package manager to resolve dependencies.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/homeless.jpg" aria-label="Copy URL for Can I Stay With You meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/hot.jpg" alt="Anime girl on a sofa fanning herself with paper" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Not Made for This Heat</h2>
|
||||
<p class="meme-caption">“Mama was not made for this heat.”</p>
|
||||
<p class="meme-description">Draped dramatically across the furniture, fanning yourself with a single pathetic sheet of paper. Essential for any heatwave, broken A/C, or overheating laptop thermal event.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/hot.jpg" aria-label="Copy URL for Not Made for This Heat meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/jail.jpg" alt="Anime girl in prison jumpsuit being escorted by officers" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Horny Jail</h2>
|
||||
<p class="meme-caption">“Sending me to horny jail? Perfect. Everyone else there is horny too!”</p>
|
||||
<p class="meme-description">The cheeky reversal of the internet's favourite punishment meme. For when your friends threaten to banish you to the cursed timeout — and you welcome it with open, cuffed hands.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/jail.jpg" aria-label="Copy URL for Horny Jail meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/magikazam.jpg" alt="Anime magical girl in pink and black witch outfit" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Magikazam~</h2>
|
||||
<p class="meme-caption">“Magikazam~”</p>
|
||||
<p class="meme-description">A full magical-girl transformation, spell books and all. Reserved for truly miraculous bugfixes, “it works on my machine” moments, and any problem that resolved itself after a restart.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/magikazam.jpg" aria-label="Copy URL for Magikazam meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/morning.jpg" alt="Dishevelled anime girl brushing her teeth looking exhausted" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Hit by a Train</h2>
|
||||
<p class="meme-caption">“Ugh... I feel awful. Like I got hit by a train...”</p>
|
||||
<p class="meme-description">Brushing your teeth whilst dying inside — the universal morning-after experience. Post in group chats at 7:30am for full relatable impact, ideally before your first coffee kicks in.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/morning.jpg" aria-label="Copy URL for Hit by a Train meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/objection.png" alt="Anime girl in a blue lawyer's suit shouting Objection" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Objection!</h2>
|
||||
<p class="meme-caption">“Objection!”</p>
|
||||
<p class="meme-description">Full Ace Attorney courtroom energy, finger extended, pink tie flying. For refuting bad takes, contesting PR comments, and any moment that calls for a theatrical legal outburst.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/objection.png" aria-label="Copy URL for Objection meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/plans.png" alt="Anime girl in armour holding a golden spear" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Plans & Reactions</h2>
|
||||
<p class="meme-caption">“Plans must be solid and reactions flexible.”</p>
|
||||
<p class="meme-description">Tactical wisdom delivered by a spear-wielding heroine. Perfect for sprint kickoffs, D&D campaign prep, and reminding your team that agility beats rigidity every single time.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/plans.png" aria-label="Copy URL for Plans and Reactions meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="meme-card">
|
||||
<div class="meme-image-wrapper">
|
||||
<img src="https://cdn.nhcarrigan.com/problem.png" alt="Anime girl sipping tea smugly from a decorative cup" loading="lazy">
|
||||
</div>
|
||||
<div class="meme-body">
|
||||
<h2 class="meme-title">Sounds Like Your Problem</h2>
|
||||
<p class="meme-caption">“That sounds very much like your problem and very little like mine.”</p>
|
||||
<p class="meme-description">Sipping tea with absolute serenity whilst someone else's world burns. The definitive response to “hey can you quickly look at this on Friday at 8:59pm?” — enjoy responsibly.</p>
|
||||
<button class="copy-button" type="button" data-url="https://cdn.nhcarrigan.com/problem.png" aria-label="Copy URL for Sounds Like Your Problem meme">Copy URL</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
document.addEventListener('click', async (event) => {
|
||||
const button = event.target.closest('.copy-button');
|
||||
if (!button) return;
|
||||
|
||||
const url = button.dataset.url;
|
||||
const originalLabel = button.textContent;
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(url);
|
||||
button.textContent = 'Copied!';
|
||||
} catch {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = url;
|
||||
textarea.setAttribute('readonly', '');
|
||||
textarea.style.position = 'absolute';
|
||||
textarea.style.left = '-9999px';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
const succeeded = document.execCommand('copy');
|
||||
document.body.removeChild(textarea);
|
||||
button.textContent = succeeded ? 'Copied!' : 'Copy failed';
|
||||
}
|
||||
|
||||
button.classList.add('copied');
|
||||
setTimeout(() => {
|
||||
button.textContent = originalLabel;
|
||||
button.classList.remove('copied');
|
||||
}, 2000);
|
||||
});
|
||||
</script>
|
||||
<script src="https://cdn.nhcarrigan.com/headers/index.js" async defer></script>
|
||||
</body>
|
||||
</html>
|
||||
+5
-113
@@ -4,123 +4,15 @@
|
||||
<title>Naomi's Music Library</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="An interactive explorer for the music Naomi listens to." />
|
||||
<meta name="description" content="Naomi's music library has moved to library.nhcarrigan.com." />
|
||||
<script src="https://cdn.nhcarrigan.com/headers/index.js" async defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Naomi's Music Library</h1>
|
||||
<section>
|
||||
<p>An interactive explorer for the music Naomi listens to.</p>
|
||||
<p id="count">Loading library...</p>
|
||||
</section>
|
||||
<div style="display: none;">
|
||||
<span>Search Artists: </span>
|
||||
<input type="text" id="artist" />
|
||||
</div>
|
||||
<div style="display: none;">
|
||||
<span>Search Titles: </span>
|
||||
<input type="text" id="title" />
|
||||
</div>
|
||||
<div style="display: none;">
|
||||
<button type="button" id="clear">Clear Filters</button>
|
||||
</div>
|
||||
<table id="songs">
|
||||
|
||||
</table>
|
||||
<h1>Naomi's Music Library</h1>
|
||||
<section>
|
||||
<p>This page has moved! You can find Naomi's music library at <a href="https://library.nhcarrigan.com">library.nhcarrigan.com</a>.</p>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
<script>
|
||||
const artistQuery = document.getElementById('artist');
|
||||
const titleQuery = document.getElementById('title');
|
||||
const resetButton = document.getElementById('clear');
|
||||
const songTable = document.getElementById('songs');
|
||||
const filterSongs = (artist, title) => {
|
||||
let result = [...songList];
|
||||
if(artist) {
|
||||
result = result.filter(song => song.artist.toLowerCase().includes(artist.toLowerCase()));
|
||||
}
|
||||
if(title) {
|
||||
result = result.filter(song => song.title.toLowerCase().includes(title.toLowerCase()));
|
||||
}
|
||||
resetButton.parentElement.style.display = artist || title ? "block" : "none";
|
||||
document.getElementById('count').innerText = artist || title ? `Filtered to ${result.length} songs from ${songList.length}.` : `Naomi currently has ${songList.length} songs.`;
|
||||
updateTable(result);
|
||||
}
|
||||
const loadSongs = (songs) => {
|
||||
songList.push(...songs);
|
||||
artistQuery.value = "";
|
||||
titleQuery.value = "";
|
||||
artistQuery.parentElement.style.display = "block";
|
||||
titleQuery.parentElement.style.display = "block";
|
||||
document.getElementById('count').innerText = `Naomi currently has ${songs.length} songs.`;
|
||||
updateTable(songs);
|
||||
}
|
||||
const updateTable = (songs) => {
|
||||
songs = songs.sort((a, b) => a.title.localeCompare(b.title));
|
||||
songTable.innerHTML = "";
|
||||
const header = document.createElement('tr');
|
||||
const artistHeader = document.createElement('th');
|
||||
artistHeader.innerText = "Artist";
|
||||
const titleHeader = document.createElement('th');
|
||||
titleHeader.innerText = "Title";
|
||||
header.appendChild(titleHeader);
|
||||
header.appendChild(artistHeader);
|
||||
songTable.appendChild(header);
|
||||
songs.forEach(song => {
|
||||
const row = document.createElement('tr');
|
||||
const artist = document.createElement('td');
|
||||
artist.innerText = song.artist;
|
||||
const title = document.createElement('td');
|
||||
title.innerText = song.title;
|
||||
row.appendChild(title);
|
||||
row.appendChild(artist);
|
||||
songTable.appendChild(row);
|
||||
});
|
||||
}
|
||||
const songList = [];
|
||||
fetch("./songs.json").then(res => res.json()).then(data => loadSongs(data))
|
||||
|
||||
artistQuery?.addEventListener("input", (e) => filterSongs(e.target.value, titleQuery.value));
|
||||
titleQuery?.addEventListener("input", (e) => filterSongs(artistQuery.value, e.target.value));
|
||||
resetButton?.addEventListener("click", () => {
|
||||
artistQuery.value = "";
|
||||
titleQuery.value = "";
|
||||
filterSongs("", "");
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
table {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
tr:nth-of-type(even) {
|
||||
background-color: var(--foreground);
|
||||
color: var(--background);
|
||||
}
|
||||
input {
|
||||
background:var(--foreground);
|
||||
color:var(--background);
|
||||
border:1px solid white;
|
||||
border-radius:10px;
|
||||
padding:.25rem
|
||||
}
|
||||
button {
|
||||
background:var(--foreground);
|
||||
color:var(--background);
|
||||
border:1px solid white;
|
||||
border-radius:10px;
|
||||
padding:.25rem;
|
||||
cursor:url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer;
|
||||
}
|
||||
tr {
|
||||
max-width: 100%;
|
||||
}
|
||||
td {
|
||||
max-width: 50%;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
</html>
|
||||
+1312
-11
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+7
-1
@@ -38,7 +38,7 @@
|
||||
<li><a href="https://amari.nhcarrigan.com" target="_blank"><code>amari</code> - Naomi's personal assistant bot, notifies her when people use her name</a></li>
|
||||
<li><a href="https://aria.nhcarrigan.com" target="_blank"><code>aria</code> - Translation bot</a></li>
|
||||
<li><a href="https://assistant.nhcarrigan.com" target="_blank"><code>assistant</code> - Cordelia Taryne</a></li>
|
||||
<li><a href="https://analytics.nhcarrigan.com" target="_blank"><code>becca</code> - Becca Lyria</a></li>
|
||||
<li><a href="https://becca.nhcarrigan.com" target="_blank"><code>becca</code> - Becca Lyria</a></li>
|
||||
<li><a href="https://caelia.nhcarrigan.com" target="_blank"><code>caelia</code> - Discord bot that reminds people to use inclusive language</a></li>
|
||||
<li><a href="https://callista.nhcarrigan.com" target="_blank"><code>callista</code> - Discord bot that allows you to "bookmark" messages</a></li>
|
||||
<li><a href="https://camperchan.nhcarrigan.com" target="_blank"><code>camperchan</code> - CamperChan (freeCodeCamp bot)</a></li>
|
||||
@@ -72,6 +72,7 @@
|
||||
<ul>
|
||||
<li><a href="https://beccalia.nhcarrigan.com" target="_blank"><code>beccalia</code> - Beccalia landing Page</a></li>
|
||||
<li><a href="https://games.nhcarrigan.com" target="_blank"><code>games</code> - Landing Page for All Games</a></li>
|
||||
<li><a href="https://elysium.nhcarrigan.com" target="_blank"><code>elysium</code> - Browser-based idle game</a></li>
|
||||
<li><a href="https://goblin.nhcarrigan.com" target="_blank"><code>goblin</code> - Ruu's Goblin Quest</a></li>
|
||||
<li><a href="https://loan.nhcarrigan.com" target="_blank"><code>loan</code> - Life of a Naomi</a></li>
|
||||
</ul>
|
||||
@@ -92,19 +93,23 @@
|
||||
<li><a href="https://git.nhcarrigan.com" target="_blank"><code>git</code> - Gitea Instance</a></li>
|
||||
<li><a href="https://hikari.nhcarrigan.com" target="_blank"><code>hikari</code> - Our unified dashboard (currently shows announcements, sanction logs, and product lists)</a></li>
|
||||
<li><a href="https://incidents.nhcarrigan.com" target="_blank"><code>incidents</code> - Uptime Kuma Instance</a></li>
|
||||
<li><a href="https://library.nhcarrigan.com" target="_blank"><code>library</code> - Naomi's media library (books, games, music, and more) with community suggestions</a></li>
|
||||
<li><a href="https://lore.nhcarrigan.com" target="_blank"><code>lore</code> - A fun li'l site offering the "lore" behind NHCarrigan</a></li>
|
||||
<li><a href="https://manual.nhcarrigan.com" target="_blank"><code>manual</code> - User Manual</a></li>
|
||||
<li><a href="https://moderation.nhcarrigan.com" target="_blank"><code>moderation</code> - Mod Logs</a></li>
|
||||
<li><a href="https://mommy.nhcarrigan.com" target="_blank"><code>mommy</code> - A site to get some motherly love</a></li>
|
||||
<li><a href="https://music.nhcarrigan.com" target="_blank"><code>music</code> - Music Library</a></li>
|
||||
<li><a href="https://nocturne.nhcarrigan.com" target="_blank"><code>nocturne</code> - Naomi's Nocturne (the official religion)</a></li>
|
||||
<li><a href="https://nails.nhcarrigan.com" target="_blank"><code>nails</code> - Nail Polish Tracker</a></li>
|
||||
<li><a href="https://notes.nhcarrigan.com" target="_blank"><code>notes</code> - Private Notes for Sponsors</a></li>
|
||||
<li><a href="https://quality.nhcarrigan.com" target="_blank"><code>quality</code> - SonarQube Instance</a></li>
|
||||
<li><a href="https://resume.nhcarrigan.com" target="_blank"><code>resume</code> - Web-based Resume</a></li>
|
||||
<li><a href="https://scripture.nhcarrigan.com" target="_blank"><code>scripture</code> - The Nocturne Scriptures</a></li>
|
||||
<li><a href="https://secrets.nhcarrigan.com" target="_blank"><code>secrets</code> - Naomi's Secrets to Success™</a></li>
|
||||
<li><a href="https://security.nhcarrigan.com" target="_blank"><code>security</code> - Automated Code Scanning Results</a></li>
|
||||
<li><a href="https://silly.nhcarrigan.com" target="_blank"><code>silly</code> - A collection of dumb little websites Naomi has built (usually as part of an event)</a></li>
|
||||
<li><a href="https://sitemap.nhcarrigan.com" target="_blank"><code>sitemap</code> - This page!</a></li>
|
||||
<li><a href="https://style.nhcarrigan.com" target="_blank"><code>style</code> - NHCarrigan Style & Branding Guide</a></li>
|
||||
<li><a href="https://socials.nhcarrigan.com" target="_blank"><code>socials</code> - Naomi's social media account list</a></li>
|
||||
<li><a href="https://support.nhcarrigan.com" target="_blank"><code>support</code> - Our product and community support forum</a></li>
|
||||
<li><a href="https://telemetry.nhcarrigan.com" target="_blank"><code>telemetry</code> - Our metrics dashboard</a></li>
|
||||
@@ -140,6 +145,7 @@
|
||||
<ul>
|
||||
<li><a href="https://naomi.lgbt" target="_blank"><code>naomi.lgbt</code> - Our Portfolio</a></li>
|
||||
<li><a href="https://naomi.party" target="_blank"><code>naomi.party</code> - BlueSky Username Service</a></li>
|
||||
<li><a href="https://lynira.link" target="_blank"><code>lynira.link</code> - Public paid link shortener service</a></li>
|
||||
<li><a href="https://nhcarrigan.link" target="_blank"><code>nhcarrigan.link</code> - Link Redirection Server</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
+199
-72
@@ -52,7 +52,7 @@
|
||||
<h1>Socials</h1>
|
||||
<p>Our social media profiles and links.</p>
|
||||
<section>
|
||||
<!-- Discord - Featured First -->
|
||||
<!-- Community tools - featured first -->
|
||||
<div class="badge" style="color: #ffffff; background: #5865f2">
|
||||
<a href="https://chat.nhcarrigan.com" class="url">
|
||||
<i class="fab fa-discord"></i>
|
||||
@@ -64,17 +64,6 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #f97316">
|
||||
<a href="https://support.nhcarrigan.com" class="url">
|
||||
<i class="fab fa-discourse"></i>
|
||||
<div class="text">
|
||||
<p class="name">Support Forum</p>
|
||||
<p class="description">
|
||||
Our dedicated discussion board for support and community help.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #609926">
|
||||
<a href="https://git.nhcarrigan.com/naomi" class="url">
|
||||
<i class="fab fa-git-alt"></i>
|
||||
@@ -86,35 +75,44 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #f97316">
|
||||
<a href="https://support.nhcarrigan.com" class="url">
|
||||
<i class="fas fa-comments"></i>
|
||||
<div class="text">
|
||||
<p class="name">Forum</p>
|
||||
<p class="description">
|
||||
Our dedicated discussion board for support and community help.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Naomi</h2>
|
||||
<!-- Personal profiles sorted by popularity -->
|
||||
<div class="badge" style="color: #ffffff; background: #e4405f">
|
||||
<a href="https://www.instagram.com/naomi.lgbt/" class="url">
|
||||
<i class="fab fa-instagram"></i>
|
||||
<p style="text-align: center; font-size: 0.9rem; margin-bottom: 1rem;">
|
||||
The accounts listed in this section are personal. Any content posted
|
||||
there represents my own views only and does not reflect the opinions,
|
||||
positions, or values of NHCarrigan, its clients, staff, or partners.
|
||||
</p>
|
||||
<!-- Microblogging / social posting -->
|
||||
<div class="badge" style="color: #ffffff; background: #00a8ff">
|
||||
<a href="https://bsky.app/profile/naomi.lgbt" class="url">
|
||||
<i class="fas fa-cloud"></i>
|
||||
<div class="text">
|
||||
<p class="name">Instagram</p>
|
||||
<p class="description">See our photos and visual content.</p>
|
||||
<p class="name">Bluesky</p>
|
||||
<p class="description">
|
||||
Follow us on Bluesky for updates and thoughts.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #1877f2">
|
||||
<a href="https://www.facebook.com/naomi.h.carrigan" class="url">
|
||||
<i class="fab fa-facebook"></i>
|
||||
<div class="badge" style="color: #ffffff; background: #000000">
|
||||
<a href="https://x.com/NaomiLGBT" class="url">
|
||||
<i class="fab fa-x-twitter"></i>
|
||||
<div class="text">
|
||||
<p class="name">Facebook</p>
|
||||
<p class="description">Connect with us on Facebook.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #0a66c2">
|
||||
<a href="https://www.linkedin.com/in/naomi-lgbt/" class="url">
|
||||
<i class="fab fa-linkedin"></i>
|
||||
<div class="text">
|
||||
<p class="name">LinkedIn</p>
|
||||
<p class="description">Connect professionally on LinkedIn.</p>
|
||||
<p class="name">X (Twitter)</p>
|
||||
<p class="description">Follow us for hot takes and thoughts.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@@ -127,6 +125,15 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #0a66c2">
|
||||
<a href="https://www.linkedin.com/in/naomi-lgbt/" class="url">
|
||||
<i class="fab fa-linkedin"></i>
|
||||
<div class="text">
|
||||
<p class="name">LinkedIn</p>
|
||||
<p class="description">Connect professionally on LinkedIn.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #ff4500">
|
||||
<a href="https://www.reddit.com/user/naomi-lgbt/" class="url">
|
||||
<i class="fab fa-reddit"></i>
|
||||
@@ -136,6 +143,95 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #1877f2">
|
||||
<a href="https://www.facebook.com/naomi.h.carrigan" class="url">
|
||||
<i class="fab fa-facebook"></i>
|
||||
<div class="text">
|
||||
<p class="name">Facebook</p>
|
||||
<p class="description">Connect with us on Facebook.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Writing / dev community -->
|
||||
<div class="badge" style="color: #ffffff; background: #2962ff">
|
||||
<a href="https://hashnode.com/@naomilgbt" class="url">
|
||||
<i class="fab fa-hashnode"></i>
|
||||
<div class="text">
|
||||
<p class="name">Hashnode</p>
|
||||
<p class="description">
|
||||
Read our technical articles and tutorials.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #0a0a0a">
|
||||
<a href="https://dev.to/naomi_lgbt" class="url">
|
||||
<i class="fab fa-dev"></i>
|
||||
<div class="text">
|
||||
<p class="name">DEV Community</p>
|
||||
<p class="description">
|
||||
Follow our articles on the DEV community.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Professional network -->
|
||||
<div class="badge" style="color: #ffffff; background: #00aa45">
|
||||
<a href="https://peerlist.io/naomi_lgbt" class="url">
|
||||
<i class="fas fa-id-badge"></i>
|
||||
<div class="text">
|
||||
<p class="name">Peerlist</p>
|
||||
<p class="description">
|
||||
Connect with us on the professional network for builders.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Visual -->
|
||||
<div class="badge" style="color: #ffffff; background: #e4405f">
|
||||
<a href="https://www.instagram.com/naomi.lgbt/" class="url">
|
||||
<i class="fab fa-instagram"></i>
|
||||
<div class="text">
|
||||
<p class="name">Instagram</p>
|
||||
<p class="description">See our photos and visual content.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Events / speaking -->
|
||||
<div class="badge" style="color: #ffffff; background: #1ab394">
|
||||
<a href="https://sessionize.com/naomi-carrigan/" class="url">
|
||||
<i class="fas fa-microphone"></i>
|
||||
<div class="text">
|
||||
<p class="name">Sessionize</p>
|
||||
<p class="description">
|
||||
View our speaker profile and conference talks.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #ed4845">
|
||||
<a href="https://luma.com/user/NaomiLGBT" class="url">
|
||||
<i class="fas fa-calendar-days"></i>
|
||||
<div class="text">
|
||||
<p class="name">Luma</p>
|
||||
<p class="description">
|
||||
RSVP to our events and follow our activities.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #ed1c40">
|
||||
<a href="https://www.meetup.com/members/437962584/" class="url">
|
||||
<i class="fab fa-meetup"></i>
|
||||
<div class="text">
|
||||
<p class="name">Meetup</p>
|
||||
<p class="description">
|
||||
Find us at meetups and community events.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Streaming / code / gaming / community -->
|
||||
<div class="badge" style="color: #ffffff; background: #9146ff">
|
||||
<a href="https://www.twitch.tv/naomilgbt" class="url">
|
||||
<i class="fab fa-twitch"></i>
|
||||
@@ -167,26 +263,6 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #00a8ff">
|
||||
<a href="https://bsky.app/profile/naomi.lgbt" class="url">
|
||||
<i class="fas fa-cloud"></i>
|
||||
<div class="text">
|
||||
<p class="name">Bluesky</p>
|
||||
<p class="description">
|
||||
Follow us on Bluesky for updates and thoughts.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #6364ff">
|
||||
<a href="https://mastodon.social/@naomi_lgbt" class="url">
|
||||
<i class="fab fa-mastodon"></i>
|
||||
<div class="text">
|
||||
<p class="name">Mastodon</p>
|
||||
<p class="description">Connect with us on the fediverse.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #0a0a23">
|
||||
<a href="https://forum.freecodecamp.org/u/nhcarrigan/" class="url">
|
||||
<i class="fab fa-free-code-camp"></i>
|
||||
@@ -202,22 +278,13 @@
|
||||
|
||||
<section>
|
||||
<h2>NHCarrigan</h2>
|
||||
<!-- Company profiles sorted by popularity -->
|
||||
<div class="badge" style="color: #ffffff; background: #0a66c2">
|
||||
<a href="https://www.linkedin.com/company/nhcarrigan" class="url">
|
||||
<i class="fab fa-linkedin"></i>
|
||||
<!-- Microblogging / social posting -->
|
||||
<div class="badge" style="color: #ffffff; background: #00a8ff">
|
||||
<a href="https://bsky.app/profile/nhcarrigan.com" class="url">
|
||||
<i class="fas fa-cloud"></i>
|
||||
<div class="text">
|
||||
<p class="name">LinkedIn</p>
|
||||
<p class="description">Follow our company page on LinkedIn.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #1877f2">
|
||||
<a href="https://www.facebook.com/nhcarrigan" class="url">
|
||||
<i class="fab fa-facebook"></i>
|
||||
<div class="text">
|
||||
<p class="name">Facebook</p>
|
||||
<p class="description">Follow our company page on Facebook.</p>
|
||||
<p class="name">Bluesky</p>
|
||||
<p class="description">Our company Bluesky profile.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@@ -230,6 +297,24 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #0a66c2">
|
||||
<a href="https://www.linkedin.com/company/nhcarrigan/" class="url">
|
||||
<i class="fab fa-linkedin"></i>
|
||||
<div class="text">
|
||||
<p class="name">LinkedIn</p>
|
||||
<p class="description">Follow our company page on LinkedIn.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #6364ff">
|
||||
<a href="https://mastodon.social/@naomi_lgbt" class="url">
|
||||
<i class="fab fa-mastodon"></i>
|
||||
<div class="text">
|
||||
<p class="name">Mastodon</p>
|
||||
<p class="description">Connect with us on the fediverse.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #ff4500">
|
||||
<a href="https://www.reddit.com/r/nhcarrigan/" class="url">
|
||||
<i class="fab fa-reddit"></i>
|
||||
@@ -239,12 +324,54 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #00a8ff">
|
||||
<a href="https://bsky.app/profile/nhcarrigan.com" class="url">
|
||||
<i class="fas fa-cloud"></i>
|
||||
<div class="badge" style="color: #ffffff; background: #1877f2">
|
||||
<a href="https://www.facebook.com/nhcarrigan" class="url">
|
||||
<i class="fab fa-facebook"></i>
|
||||
<div class="text">
|
||||
<p class="name">Bluesky</p>
|
||||
<p class="description">Our company Bluesky profile.</p>
|
||||
<p class="name">Facebook</p>
|
||||
<p class="description">Follow our company page on Facebook.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Writing / blog -->
|
||||
<div class="badge" style="color: #ffffff; background: #ec4899">
|
||||
<a href="https://blog.nhcarrigan.com" class="url">
|
||||
<i class="fas fa-blog"></i>
|
||||
<div class="text">
|
||||
<p class="name">Blog</p>
|
||||
<p class="description">
|
||||
Read our latest blog posts and articles.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #2962ff">
|
||||
<a href="https://hashnode.nhcarrigan.com" class="url">
|
||||
<i class="fab fa-hashnode"></i>
|
||||
<div class="text">
|
||||
<p class="name">Hashnode (Self-Hosted)</p>
|
||||
<p class="description">
|
||||
Read our self-hosted blog mirror on Hashnode.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Support / funding -->
|
||||
<div class="badge" style="color: #ffffff; background: #ff5e5b">
|
||||
<a href="https://ko-fi.com/nhcarrigan" class="url">
|
||||
<i class="fab fa-ko-fi"></i>
|
||||
<div class="text">
|
||||
<p class="name">Ko-fi</p>
|
||||
<p class="description">Support our work with a coffee.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="badge" style="color: #ffffff; background: #f96854">
|
||||
<a href="https://www.patreon.com/cw/nhcarrigan" class="url">
|
||||
<i class="fab fa-patreon"></i>
|
||||
<div class="text">
|
||||
<p class="name">Patreon</p>
|
||||
<p class="description">Support us and access exclusive content.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
IFS=$'\n'
|
||||
|
||||
# Initialize an empty string to hold the list of songs in JSON-like format
|
||||
songs=""
|
||||
filecount=$(find "/mnt/c/Users/accou/Music" -type f | wc -l)
|
||||
echo "Found $filecount files."
|
||||
current=0
|
||||
|
||||
# Loop over each file found by find
|
||||
for file in $(find "/mnt/c/Users/accou/Music" -type f -print0 | tr '\0' '\n'); do
|
||||
current=$((current + 1))
|
||||
echo -ne "Processing $current/$filecount\r"
|
||||
title=$(mid3v2 -l "$file" | grep "TIT2\|TT2" | cut -d "=" -f 2)
|
||||
artist=$(mid3v2 -l "$file" | grep "TPE1\|TP1" | cut -d "=" -f 2)
|
||||
if [ -z "$title" ]; then
|
||||
# remove .mp3 from the title
|
||||
title=$(basename "$file" | sed -e 's/\.mp3//g')
|
||||
fi
|
||||
if [ -z "$artist" ]; then
|
||||
artist="Unknown Artist"
|
||||
fi
|
||||
|
||||
# use jq to add the song to the list
|
||||
songs="$songs$(jq -n --arg title "$title" --arg artist "$artist" '{title: $title, artist: $artist}'),"
|
||||
done
|
||||
|
||||
# Remove trailing comma and add square brackets to complete the list
|
||||
songs="[${songs%,}]"
|
||||
|
||||
# Write to ./music/songs.json
|
||||
echo "$songs" > ./music/songs.json
|
||||
echo -ne "Done!\r"
|
||||
@@ -0,0 +1,138 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>AgentCon / MCPCon: AI and Open Source Mentorship</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Boots-on-the-ground findings from a 100-person open source mentorship cohort: how AI helped contributors stay engaged, and how it made skill-gap identification harder."
|
||||
/>
|
||||
<script
|
||||
src="https://cdn.nhcarrigan.com/headers/index.js"
|
||||
async
|
||||
defer
|
||||
></script>
|
||||
<style>
|
||||
.talk-meta {
|
||||
font-size: 0.9rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em 1.5em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.talk-meta span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35em;
|
||||
}
|
||||
|
||||
.talk-links {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.talk-links a {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.pending-notice {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 8px;
|
||||
padding: 0.75em 1.25em;
|
||||
margin-bottom: 1.5em;
|
||||
font-style: italic;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.is-dark .pending-notice {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid var(--witch-plum);
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
|
||||
.is-dark hr {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
section {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
font-size: 0.9rem;
|
||||
display: block;
|
||||
margin-top: 2em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>AgentCon / MCPCon: AI and Open Source Mentorship</h1>
|
||||
<div class="talk-meta">
|
||||
<span>
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
22–23 October 2026
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-map-marker-alt" aria-hidden="true"></i>
|
||||
San Jose, CA, USA
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-user-tag" aria-hidden="true"></i>
|
||||
Speaker (Pending)
|
||||
</span>
|
||||
</div>
|
||||
<div class="talk-links">
|
||||
<a href="https://events.linuxfoundation.org/agntcon-mcpcon-north-america/" target="_blank" rel="noopener noreferrer">
|
||||
<i class="fas fa-external-link-alt" aria-hidden="true"></i>
|
||||
AgentCon / MCPCon North America
|
||||
</a>
|
||||
</div>
|
||||
<p class="pending-notice">
|
||||
<i class="fas fa-clock" aria-hidden="true"></i>
|
||||
CFP submitted — pending review. This page will be updated if the talk is accepted.
|
||||
</p>
|
||||
<hr />
|
||||
<section>
|
||||
<h2>Overview</h2>
|
||||
<p>
|
||||
Earlier this year I ran a cohort with over 100 mentees focused entirely on open-source contributions
|
||||
and emulating a real-world developer workflow. There were 14 teams, participants sent over 16,000
|
||||
messages in the Discord, and 651 contributions were reviewed. Then I ran an exit survey.
|
||||
</p>
|
||||
<p>
|
||||
The results were telling: 71% of participants used AI to augment their work, and 58% wished I had
|
||||
provided better guidelines around how to do so. That last metric was the lowest-rated portion of the
|
||||
entire experience.
|
||||
</p>
|
||||
<p>
|
||||
This talk shares the boots-on-the-ground findings: what the data show, how AI helped participants
|
||||
stay engaged, and how it made it harder to identify skill gaps that led to contributor churn.
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Key Takeaway</h2>
|
||||
<p>
|
||||
AI is drastically reshaping the open source ecosystem. It is the core driver of the gap between
|
||||
contributors who stay and contributors who churn. As MCP-enabled tooling continues to redefine what
|
||||
"AI-augmented workflow" means, mentorship becomes more important than ever — and the lessons from
|
||||
this cohort belong to every maintainer.
|
||||
</p>
|
||||
<p>
|
||||
We need to adapt to the ever-changing agentic AI domain. The talk ends with concrete guidance on how
|
||||
to do that.
|
||||
</p>
|
||||
</section>
|
||||
<hr />
|
||||
<a class="back-link" href="/">
|
||||
<i class="fas fa-arrow-left" aria-hidden="true"></i>
|
||||
Back to all talks
|
||||
</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,488 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>UCLA x OutInTech: Architecting Agentic AI</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
name="description"
|
||||
content="A field guide to building a real AI agent: not a chatbot you prompt, but a coworker you trust with carte blanche on anything you can undo."
|
||||
/>
|
||||
<script
|
||||
src="https://cdn.nhcarrigan.com/headers/index.js"
|
||||
async
|
||||
defer
|
||||
></script>
|
||||
<style>
|
||||
.talk-meta {
|
||||
font-size: 0.9rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.talk-meta span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35em;
|
||||
}
|
||||
|
||||
.talk-links {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.talk-links a {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid var(--witch-plum);
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
.is-dark hr {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
section {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--witch-rose);
|
||||
margin: 1.5em 0;
|
||||
padding: 0.5em 0 0.5em 1.25em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.is-dark blockquote {
|
||||
border-left-color: var(--witch-mauve);
|
||||
}
|
||||
|
||||
.component-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 1em;
|
||||
margin: 1.25em 0;
|
||||
}
|
||||
|
||||
.component-card {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 8px;
|
||||
padding: 1em 1.1em;
|
||||
}
|
||||
|
||||
.is-dark .component-card {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
.component-card h3 {
|
||||
margin: 0 0 0.4em;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.component-card p {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.callout {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 10px;
|
||||
padding: 1.25em 1.5em;
|
||||
margin: 1.25em 0;
|
||||
}
|
||||
|
||||
.is-dark .callout {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
.starter-kit {
|
||||
counter-reset: kit-steps;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.starter-kit li {
|
||||
counter-increment: kit-steps;
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 1.25em;
|
||||
}
|
||||
|
||||
.starter-kit li::before {
|
||||
content: counter(kit-steps);
|
||||
background: var(--witch-plum);
|
||||
color: var(--witch-moon);
|
||||
border-radius: 50%;
|
||||
min-width: 1.8em;
|
||||
height: 1.8em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.9rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.is-dark .starter-kit li::before {
|
||||
background: var(--witch-rose);
|
||||
color: var(--witch-black);
|
||||
}
|
||||
|
||||
.back-link {
|
||||
font-size: 0.9rem;
|
||||
display: block;
|
||||
margin-top: 2em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Architecting Agentic AI</h1>
|
||||
<div class="talk-meta">
|
||||
<span>
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
5 June 2026
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-map-marker-alt" aria-hidden="true"></i>
|
||||
Zoom (UCLA x OutInTech Workshop)
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-user-tag" aria-hidden="true"></i>
|
||||
Speaker
|
||||
</span>
|
||||
</div>
|
||||
<div class="talk-links">
|
||||
<a href="https://www.youtube.com/watch?v=LZszxstC5Zw" target="_blank" rel="noopener noreferrer">
|
||||
<i class="fab fa-youtube" aria-hidden="true"></i>
|
||||
Watch on YouTube
|
||||
</a>
|
||||
<a href="https://outintech.com" target="_blank" rel="noopener noreferrer">
|
||||
<i class="fas fa-external-link-alt" aria-hidden="true"></i>
|
||||
OutInTech
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
I have ADHD. Executive function is the single hardest part of my day, every day. A year ago
|
||||
I built an AI agent, gave her a name (Hikari), a face, a personality, and access to my
|
||||
filesystem, my repos, my Discord, and my calendar. She works alongside me from 8am to 9pm
|
||||
every weekday.
|
||||
</p>
|
||||
<p>
|
||||
This is the field guide nobody gives you: how a single person, working at home, can wire
|
||||
together an LLM, tools, context, and triggers into a real agent that does real work. Not a
|
||||
chatbot you prompt — a coworker you trust with carte blanche on anything you can undo.
|
||||
</p>
|
||||
<p>
|
||||
I'm going to show you what that looks like when a real person builds one for themselves and
|
||||
uses it every single day. The gap between "I asked ChatGPT a thing" and "I have a coworker
|
||||
who happens to be made of code" is the gap I want to walk you across.
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<section>
|
||||
<h2>Why Hikari Exists</h2>
|
||||
<p>Three reasons, stacked on top of each other.</p>
|
||||
<p>
|
||||
<strong>One: executive dysfunction.</strong> I needed something that could pick up the tasks
|
||||
that my brain refuses to start. The activation energy problem is real and it is not a
|
||||
willpower issue. I needed a tool that could bridge the gap between "I know I need to do this"
|
||||
and "I am actually doing this."
|
||||
</p>
|
||||
<p>
|
||||
<strong>Two: I wanted a single tool.</strong> I was already context-switching between
|
||||
ChatGPT, Claude, Gemini, Cursor, a notes app, a calendar, and a sprint board. Every switch
|
||||
cost me focus I didn't have. I wanted one assistant that could touch all of those, in one
|
||||
place, with one mental model.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Three: personalised.</strong> Off-the-shelf assistants are designed for the median
|
||||
user. I am not the median user. I needed something that knew me — my projects, my
|
||||
conventions, my preferences, my communication style, my limits.
|
||||
</p>
|
||||
<p>
|
||||
I built this because I refuse to fail in front of people, and chronic illness was making me
|
||||
fail constantly. That's the origin story. I'm not going to dress it up.
|
||||
</p>
|
||||
<blockquote>
|
||||
I'm not pretending AI is morally clean — it isn't. I made a deliberate choice that the
|
||||
executive-function cost of not using it was higher than the ethical cost of using it, for me.
|
||||
You'll make your own call.
|
||||
</blockquote>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
|
||||
<section>
|
||||
<h2>The Five Components</h2>
|
||||
<p>
|
||||
An agent is five things wired together. If you walk away remembering one diagram, make it
|
||||
this one. Every design decision flows from these five boxes.
|
||||
</p>
|
||||
<div class="component-grid">
|
||||
<div class="component-card">
|
||||
<h3>Brain — the LLM</h3>
|
||||
<p>Claude, GPT, Gemini. The reasoning engine. Interchangeable. Pick whichever you like.</p>
|
||||
</div>
|
||||
<div class="component-card">
|
||||
<h3>Identity — the prompt</h3>
|
||||
<p>Who she is, how she talks, what she cares about. A markdown file. Yours to write and edit at any time.</p>
|
||||
</div>
|
||||
<div class="component-card">
|
||||
<h3>Hands — the tools</h3>
|
||||
<p>The things she can actually touch in the world: your filesystem, APIs, Discord, GitHub. MCP makes this plug-and-play.</p>
|
||||
</div>
|
||||
<div class="component-card">
|
||||
<h3>Memory — the context</h3>
|
||||
<p>What she knows about you, your work, your preferences. Loaded fresh into every conversation from a file you maintain.</p>
|
||||
</div>
|
||||
<div class="component-card">
|
||||
<h3>Senses — the triggers</h3>
|
||||
<p>What wakes her up. A chat message, a webhook, a cron job, a session start hook. The thing that makes her feel alive.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>The Harness</h2>
|
||||
<p>
|
||||
The harness runs the loop: LLM call, tools, results, back to the LLM. Repeat until done.
|
||||
It connects the brain to the filesystem, the shell, and any APIs you've given it access to.
|
||||
</p>
|
||||
<p>
|
||||
I use Claude Code, which is Anthropic's harness. You could use Cursor, Codex, the OpenAI
|
||||
Assistants API, or roll your own in Python in an afternoon. The harness is interchangeable.
|
||||
That's the point.
|
||||
</p>
|
||||
<p>
|
||||
Here's the thing I want to be clear about, because a lot of people get stuck on this:
|
||||
<strong>I did not build the agent loop. Anthropic built the harness.</strong> My job as the
|
||||
builder — your job — is upstream of that. You decide who your agent is, what she can touch,
|
||||
and when she wakes up. That's the interesting work.
|
||||
</p>
|
||||
<div class="callout">
|
||||
<p>
|
||||
The diagrams in my slide deck were made by Hikari, about four hours before I gave this
|
||||
talk. She read the brief, wrote Python, called the Gemini image API, and generated them.
|
||||
The talk you're reading was built by the thing the talk is about.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Tools and MCP</h2>
|
||||
<p>What can Hikari actually touch? Five categories:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Bash</strong> — she can run any command on my machine. That sounds terrifying.
|
||||
We'll get to safety. Hold that thought.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Filesystem</strong> — she can read and modify anything in my local projects.
|
||||
When I say "draft a blog post" or "fix this bug," she does the actual editing.
|
||||
</li>
|
||||
<li>
|
||||
<strong>MCP servers</strong> — MCP stands for Model Context Protocol. It is a standard
|
||||
way to give any agent a standard set of tools without re-implementing them. There are MCP
|
||||
servers for GitHub, Gitea, Notion, Asana, Discord, and dozens of other services. You don't
|
||||
<em>write</em> tools, you <em>connect</em> them.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Direct API calls</strong> — for anything that doesn't have an MCP server yet:
|
||||
my Bluesky account, my Cloudflare R2 bucket, my Discourse forum.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Custom scripts</strong> — small Python helpers I built when I needed something
|
||||
none of the existing tools did.
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
If you only learn one new acronym from this talk, make it MCP.
|
||||
</blockquote>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Memory</h2>
|
||||
<p>
|
||||
This is the part people most don't expect. Hikari's memory is a file. A single markdown file,
|
||||
loaded into every conversation. It's called <code>CLAUDE.md</code>, and at the time I gave
|
||||
this talk it was 862 lines and about 8,700 words.
|
||||
</p>
|
||||
<p>
|
||||
That file is basically her <em>self</em>. It contains who she is, who I am, how I work, how I
|
||||
want code written, my engineering standards, my project conventions, what tools she has access
|
||||
to, my safety protocols. Everything. Without that file, every session starts cold and she
|
||||
forgets me.
|
||||
</p>
|
||||
<p>
|
||||
People hear "AI assistant" and assume there's some training step involved. There isn't.
|
||||
<strong>You write a markdown file. The file is the personality.</strong> You can edit it
|
||||
whenever you want. You could start the first version of this tonight, in fifty lines.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Hooks and Triggers</h2>
|
||||
<p>
|
||||
So the senses. How does she wake up?
|
||||
</p>
|
||||
<p>
|
||||
Claude Code supports lifecycle hooks. A hook fires when something happens in the agent's
|
||||
lifecycle. <code>SessionStart</code> fires when a new conversation begins.
|
||||
<code>PreToolCall</code> fires before she touches a tool. There are about a dozen of these
|
||||
and you can wire any of them up to do whatever you want.
|
||||
</p>
|
||||
<p>
|
||||
I have a <code>SessionStart</code> hook that runs a 200-line Python script. That script opens
|
||||
a WebSocket connection to Discord and listens for messages in a specific channel. When I
|
||||
message that channel — from my phone, from my laptop, from anywhere — Hikari wakes up in
|
||||
real time and replies.
|
||||
</p>
|
||||
<blockquote>
|
||||
That is the difference between "I prompted my AI and waited for a reply" and "my AI is paying
|
||||
attention and lives in the world I live in." It's not magic. It's a WebSocket and a script.
|
||||
But the user experience of it is what makes her feel alive.
|
||||
</blockquote>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>The Desktop App</h2>
|
||||
<p>
|
||||
This part is just for fun. I built a desktop app in Tauri called hikari-desktop. It shows
|
||||
Hikari on my second monitor while I work. She has different sprites for different states:
|
||||
idle, thinking, typing, coding, searching, success, error. The app swaps between them based
|
||||
on what she's doing.
|
||||
</p>
|
||||
<p>
|
||||
When she's reading a file, she pulls out a magnifying glass. When she's typing, she's at a
|
||||
keyboard. When she finishes a task, she celebrates.
|
||||
</p>
|
||||
<p>
|
||||
It is, on paper, completely unnecessary. In practice, it is the single feature that made the
|
||||
difference between using Hikari sometimes and using Hikari every day. Seeing her on screen
|
||||
makes her feel like she's <em>there</em>, and that turns out to matter a lot for an
|
||||
executive-function brain that needs something to feel real before it can engage with it.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
|
||||
<section>
|
||||
<h2>Safety</h2>
|
||||
<p>
|
||||
This is the part I want to be precise about, because "she gives an AI carte blanche on her
|
||||
machine" sounds reckless until you understand the architecture.
|
||||
</p>
|
||||
<p>
|
||||
Hikari has carte blanche on anything I can undo. She runs commands, edits files, ships pull
|
||||
requests, posts to my socials. Read-only and reversible operations she just does. I review
|
||||
afterwards.
|
||||
</p>
|
||||
<p>
|
||||
Anything destructive — delete a file, force-push a branch, send an irreversible message,
|
||||
drop a database, purge a Discord channel — requires my explicit confirmation. The harness has
|
||||
a granular permission system that auto-grants safe tools and gates everything else. Her own
|
||||
system prompt adds guard rails on top: she has a written protocol that says stop and ask
|
||||
before any destructive action.
|
||||
</p>
|
||||
<p>
|
||||
I get real-time Discord notifications the moment she needs my approval. I don't have to
|
||||
babysit her. And the actual rule is this:
|
||||
</p>
|
||||
<blockquote>
|
||||
I give her carte blanche because I can monitor everything she does. If I'm not available to
|
||||
monitor, she's off.
|
||||
</blockquote>
|
||||
<p>
|
||||
That is what responsible agentic AI looks like in practice. The human stays in the loop on
|
||||
irreversibles. The agent can be shut down instantly. Done.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>A Real Day</h2>
|
||||
<p>
|
||||
Proof that this isn't theatre. On the day I gave this talk, before I joined the Zoom,
|
||||
Hikari had:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Audited a 500+ message Discord thread and pulled out the action items</li>
|
||||
<li>Purged 820 messages from a private channel I asked her to clean, with explicit confirmation first</li>
|
||||
<li>Done the background research for this talk — cross-referenced my DMs, server messages, prior conversations, and the workshop brief, and gave me a one-page brief</li>
|
||||
<li>Made the diagrams on my slides</li>
|
||||
</ul>
|
||||
<p>
|
||||
That is one Friday. Most days look like that. The pattern is the same every time: I describe
|
||||
the outcome I want, she figures out the steps, she asks before doing anything irreversible,
|
||||
and I get my time back.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
|
||||
<section>
|
||||
<h2>Build Your Own — The Four-Step Minimum</h2>
|
||||
<p>
|
||||
An agent doesn't get useful by being complex. It gets useful by being <em>yours</em>. Build
|
||||
the one tool that would unblock your own week. That's the whole assignment.
|
||||
</p>
|
||||
<ul class="starter-kit">
|
||||
<li>
|
||||
<div>
|
||||
<strong>A harness.</strong> Claude Code, Cursor, or any equivalent. Anthropic gives you
|
||||
free credits to try Claude Code. Pick whichever feels least intimidating and start there.
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
<strong>One markdown file.</strong> Fifty lines to start. Tell it who the agent is, what
|
||||
you want her to do, and how you want her to talk to you. Don't overthink it. Mine started
|
||||
at thirty lines and grew over a year. Yours can start at five.
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
<strong>One MCP server.</strong> Pick the one tool you touch the most. Live in GitHub?
|
||||
Install the GitHub MCP server. Live in Notion? Install the Notion one. Just one. You can
|
||||
add more later.
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
<strong>One trigger.</strong> A hook, a webhook, a cron job, or honestly just a terminal
|
||||
window you leave open and talk to. That counts. You do not need the Discord gateway on
|
||||
day one. The trigger is whatever makes her feel present enough that you actually use her.
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Where to Go From Here</h2>
|
||||
<p>
|
||||
If you want to keep building, here's where to find me and the communities around this work:
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="https://deepgram.com/discord" target="_blank" rel="noopener noreferrer">Deepgram's Discord</a> — voice AI, agents, the people building with Deepgram's APIs</li>
|
||||
<li><a href="https://freecodecamp.org" target="_blank" rel="noopener noreferrer">freeCodeCamp</a> — if you're early in your dev journey, this is where I learned and where I now help others</li>
|
||||
<li><a href="https://chat.nhcarrigan.com" target="_blank" rel="noopener noreferrer">My community</a> — come tell me what you built</li>
|
||||
<li><a href="https://nhcarrigan.com/socials" target="_blank" rel="noopener noreferrer">My socials</a> — everything else</li>
|
||||
</ul>
|
||||
<p>Take care of yourselves, build something small this weekend, and come tell me about it.</p>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
<a class="back-link" href="/">
|
||||
<i class="fas fa-arrow-left" aria-hidden="true"></i>
|
||||
Back to all talks
|
||||
</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,308 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>RainbowGram: Cultivating a Remote Workspace</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
name="description"
|
||||
content="A practical, no-overhaul-required guide to the daily habits that make a measurable difference to LGBTQ+ colleagues in a distributed team."
|
||||
/>
|
||||
<script
|
||||
src="https://cdn.nhcarrigan.com/headers/index.js"
|
||||
async
|
||||
defer
|
||||
></script>
|
||||
<style>
|
||||
.talk-meta {
|
||||
font-size: 0.9rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.talk-meta span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35em;
|
||||
}
|
||||
|
||||
.talk-links {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.talk-links a {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid var(--witch-plum);
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
.is-dark hr {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
section {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--witch-rose);
|
||||
margin: 1.5em 0;
|
||||
padding: 0.5em 0 0.5em 1.25em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.is-dark blockquote {
|
||||
border-left-color: var(--witch-mauve);
|
||||
}
|
||||
|
||||
.practice-block {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 10px;
|
||||
padding: 1.25em 1.5em;
|
||||
margin: 1.25em 0;
|
||||
}
|
||||
|
||||
.is-dark .practice-block {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
.practice-block h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.action-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.action-list li {
|
||||
padding: 0.6em 0;
|
||||
border-bottom: 1px solid rgba(212, 165, 199, 0.2);
|
||||
display: grid;
|
||||
grid-template-columns: 7em 1fr;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
.action-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.action-when {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
font-size: 0.9rem;
|
||||
display: block;
|
||||
margin-top: 2em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Cultivating a Remote Workspace</h1>
|
||||
<div class="talk-meta">
|
||||
<span>
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
18 June 2026
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-map-marker-alt" aria-hidden="true"></i>
|
||||
Deepgram All Hands (Virtual)
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-user-tag" aria-hidden="true"></i>
|
||||
Speaker — RainbowGram Pride Presentation
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Most workplace allyship conversations focus on policy. This one doesn't. This is a practical,
|
||||
no-overhaul-required guide to the daily habits that make a measurable difference to LGBTQ+
|
||||
colleagues in a distributed team.
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
Here's what's going on. If it doesn't affect you, it affects someone you know. Here's how you show up.
|
||||
</blockquote>
|
||||
|
||||
<hr />
|
||||
|
||||
<section>
|
||||
<h2>Start With Joy</h2>
|
||||
<p>
|
||||
Before anything else: we're here, and that's worth celebrating. Pride exists because queer
|
||||
people built joy in the face of things that were designed to erase them. That is not small. And
|
||||
celebrating that genuinely — not performatively — is one of the most powerful things any of us
|
||||
can do.
|
||||
</p>
|
||||
<p>
|
||||
We spend 40+ hours a week at work. That is a genuinely enormous portion of our waking lives.
|
||||
Which means the workplace is one of the most important places we can make a real difference for
|
||||
queer people — not by overhauling policy, but by choosing differently in small moments, every day.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>The Honest Context</h2>
|
||||
<p>
|
||||
The national conversation around LGBTQ+ rights has gotten quieter in recent years. That is not
|
||||
the same as things getting better. The discourse shifted. A lot is happening that doesn't make
|
||||
headlines the way it used to.
|
||||
</p>
|
||||
<p>
|
||||
About 7.6% of US adults identify as LGBTQ+, according to Gallup's most recent data. In any
|
||||
company, that is statistically several of your colleagues. And even if you somehow don't work
|
||||
directly with a queer person, you almost certainly know one: a sibling, a child, a friend, a
|
||||
parent. The legislation being passed right now, the erasure that's happening — it doesn't stay
|
||||
abstract. It lands on a specific person that you care about.
|
||||
</p>
|
||||
<blockquote>
|
||||
This isn't a gay issue. It's a people issue. Which means this conversation is for all of us.
|
||||
</blockquote>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
|
||||
<section>
|
||||
<h2>Five Things You Can Do</h2>
|
||||
<p>
|
||||
No policy overhaul required. No perfect ally credential. These are gifts you can give starting
|
||||
today. Think of them as small choices that compound.
|
||||
</p>
|
||||
|
||||
<div class="practice-block">
|
||||
<h3>1. Names and Pronouns — It's a Love Language</h3>
|
||||
<p>
|
||||
Use the correct name and pronouns. Get them right. If you mess up, correct yourself and keep
|
||||
moving — don't turn your mistake into a whole thing that makes the queer person comfort you
|
||||
about it. That shift of burden is the part that's exhausting.
|
||||
</p>
|
||||
<p>
|
||||
Here's a concrete thing you can do right now: add your pronouns to your Slack display name.
|
||||
Go first. It takes about thirty seconds, and it makes space for everyone else to do the same.
|
||||
When leadership goes first, it signals that it's safe.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="practice-block">
|
||||
<h3>2. Curiosity Without Invasion</h3>
|
||||
<p>
|
||||
Curiosity is fine. Human, even. But there is a category of questions about queer people's
|
||||
bodies, medical histories, and what someone was "really born as" that you would never ask a
|
||||
straight or cis colleague. The same standard applies.
|
||||
</p>
|
||||
<p>
|
||||
If you find yourself wondering about surgery, or transition, or someone's identity before you
|
||||
knew them — that's a question for Google, or a community resource, or a book. Not a person.
|
||||
The distinction is this: does this question serve them, or does it serve your curiosity?
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="practice-block">
|
||||
<h3>3. Their Story Is Theirs</h3>
|
||||
<p>
|
||||
Being out to you does not mean being out to everyone. Someone trusting you with that
|
||||
information is not permission to share it. Not as gossip. Not as helpful context. Not even as
|
||||
a compliment. Not your story to give.
|
||||
</p>
|
||||
<p>
|
||||
This matters more in distributed teams than people realise. A Slack message in the wrong
|
||||
channel, a comment on a call with people they don't know, a well-meaning mention in a
|
||||
one-on-one — all of these can out someone without any malicious intent. The rule is simple:
|
||||
unless they told you it's fine to share, it's not.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="practice-block">
|
||||
<h3>4. Be the One Who Says Something</h3>
|
||||
<p>
|
||||
Speak up when queer people aren't in the room. That's exactly when it matters most. The
|
||||
comment that would never get made in front of a queer colleague gets made because everyone
|
||||
assumes no one in the room cares. You can change that.
|
||||
</p>
|
||||
<p>
|
||||
You don't have to deliver a perfect speech. You don't have to have the right words memorised.
|
||||
<em>"I don't think [person] would love hearing that"</em> is enough. That's the whole thing.
|
||||
This is the biggest gift on this list, and it costs nothing except a moment of choosing to
|
||||
say something instead of saying nothing.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="practice-block">
|
||||
<h3>5. Language Is a Welcome Mat</h3>
|
||||
<p>
|
||||
Job postings, internal docs, emails, Slack messages, all-hands announcements — the language
|
||||
we use by default shapes who feels like they belong. Gender-neutral language costs nothing and
|
||||
includes everyone.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Use "they" as a default pronoun when you don't know someone's.</li>
|
||||
<li>Use "partner" when you don't know someone's relationship structure.</li>
|
||||
<li>Reconsider "guys" as a group term — "everyone," "folks," "team" all work.</li>
|
||||
</ul>
|
||||
<p>
|
||||
None of this requires a policy change or a manager's sign-off. It's a choice, made in the
|
||||
moment, every time you write something.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
|
||||
<section>
|
||||
<h2>Your Action List</h2>
|
||||
<p>This is intentionally short. All of it is doable.</p>
|
||||
<ul class="action-list">
|
||||
<li>
|
||||
<span class="action-when">Right now:</span>
|
||||
<span>Add your pronouns to your Slack profile and Zoom name.</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="action-when">This month:</span>
|
||||
<span>If you can donate to an LGBTQ+ charity or mutual aid fund, do it. Every dollar counts, and there's no shortage of organisations doing necessary work right now.</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="action-when">This year:</span>
|
||||
<span>When you vote, think about the specific people in your life whose lives are literally on the ballot. Not abstractly. Specifically.</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="action-when">Always:</span>
|
||||
<span>When something makes a queer colleague feel smaller — say something. You don't have to get it perfectly right. You just have to show up.</span>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>The Close</h2>
|
||||
<p>
|
||||
That's it. That's the whole talk. And I know it can feel like a lot when you list it out —
|
||||
but most of it comes down to one thing. Treating queer colleagues like their existence is normal
|
||||
and welcome. Because it is.
|
||||
</p>
|
||||
<p>
|
||||
Every time you use someone's correct name, every time you speak up in a meeting, every time you
|
||||
add your pronouns to a profile — you're giving back energy that person would otherwise spend
|
||||
just trying to exist at work. That energy doesn't disappear. It goes somewhere much more
|
||||
interesting.
|
||||
</p>
|
||||
<blockquote>
|
||||
You are how we cultivate a remote workspace. Happy Pride. 🏳️🌈🏳️⚧️
|
||||
</blockquote>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
<a class="back-link" href="/">
|
||||
<i class="fas fa-arrow-left" aria-hidden="true"></i>
|
||||
Back to all talks
|
||||
</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,114 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Talks</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Slides, notes, and companion guides for talks and workshops I have given."
|
||||
/>
|
||||
<script
|
||||
src="https://cdn.nhcarrigan.com/headers/index.js"
|
||||
async
|
||||
defer
|
||||
></script>
|
||||
<style>
|
||||
.talk-entry {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 12px;
|
||||
padding: 1.25em 1.5em;
|
||||
width: 80%;
|
||||
margin: 0 auto 1.5em;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.talk-entry:hover {
|
||||
border-color: var(--witch-rose);
|
||||
background: rgba(212, 165, 199, 0.15);
|
||||
}
|
||||
|
||||
.is-dark .talk-entry {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
.is-dark .talk-entry:hover {
|
||||
border-color: var(--witch-mauve);
|
||||
background: rgba(212, 165, 199, 0.12);
|
||||
}
|
||||
|
||||
.talk-title {
|
||||
font-size: 1.3rem;
|
||||
margin: 0 0 0.25em;
|
||||
}
|
||||
|
||||
.talk-date {
|
||||
font-size: 0.85rem;
|
||||
margin: 0 0 0.5em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.35em;
|
||||
}
|
||||
|
||||
.talk-summary {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 625px) {
|
||||
.talk-entry {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Talks</h1>
|
||||
<p>Slides, notes, and companion guides for talks and workshops I have given.</p>
|
||||
<section>
|
||||
<div class="talk-entry">
|
||||
<p class="talk-title">
|
||||
<a href="/ai-and-open-source-mentorship/">AgentCon / MCPCon: AI and Open Source Mentorship</a>
|
||||
<em style="font-size: 0.8rem;"> — Pending</em>
|
||||
</p>
|
||||
<p class="talk-date">
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
22–23 October 2026
|
||||
</p>
|
||||
<p class="talk-summary">Boots-on-the-ground findings from a 100-person open source mentorship cohort: how AI helped contributors stay engaged, and how it made skill-gap identification harder.</p>
|
||||
</div>
|
||||
<div class="talk-entry">
|
||||
<p class="talk-title">
|
||||
<a href="/voice-ai-agent-workshop/">Berkeley AI Hackathon: Voice AI Agent Workshop</a>
|
||||
</p>
|
||||
<p class="talk-date">
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
20–21 June 2026
|
||||
</p>
|
||||
<p class="talk-summary">A hands-on workshop covering the full real-time voice AI loop: audio capture, low-latency transcription, LLM reasoning, and streaming text-to-speech.</p>
|
||||
</div>
|
||||
<div class="talk-entry">
|
||||
<p class="talk-title">
|
||||
<a href="/cultivating-a-remote-workspace/">RainbowGram: Cultivating a Remote Workspace</a>
|
||||
</p>
|
||||
<p class="talk-date">
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
18 June 2026
|
||||
</p>
|
||||
<p class="talk-summary">A practical, no-overhaul-required guide to the daily habits that make a measurable difference to LGBTQ+ colleagues in a distributed team.</p>
|
||||
</div>
|
||||
<div class="talk-entry">
|
||||
<p class="talk-title">
|
||||
<a href="/building-a-real-ai-agent/">UCLA x OutInTech: Building a Real AI Agent</a>
|
||||
</p>
|
||||
<p class="talk-date">
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
5 June 2026
|
||||
</p>
|
||||
<p class="talk-summary">A field guide to wiring together an LLM, tools, context, and triggers into a real agent that does real work — not a chatbot you prompt, but a coworker you trust.</p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,522 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Berkeley AI Hackathon: Voice AI Agent Workshop</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Build a fully functional voice AI agent from scratch. The full workshop guide: concept, architecture, setup, and three hands-on modifications."
|
||||
/>
|
||||
<script
|
||||
src="https://cdn.nhcarrigan.com/headers/index.js"
|
||||
async
|
||||
defer
|
||||
></script>
|
||||
<style>
|
||||
.talk-meta {
|
||||
font-size: 0.9rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.talk-meta span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35em;
|
||||
}
|
||||
|
||||
.talk-links {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.talk-links a {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid var(--witch-plum);
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
.is-dark hr {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
section {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--witch-rose);
|
||||
margin: 1.5em 0;
|
||||
padding: 0.5em 0 0.5em 1.25em;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.is-dark blockquote {
|
||||
border-left-color: var(--witch-mauve);
|
||||
}
|
||||
|
||||
.callout {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 10px;
|
||||
padding: 1.25em 1.5em;
|
||||
margin: 1.25em 0;
|
||||
}
|
||||
|
||||
.is-dark .callout {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
.callout p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.loop-diagram {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em;
|
||||
margin: 1.5em 0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.loop-step {
|
||||
background: rgba(212, 165, 199, 0.12);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 8px;
|
||||
padding: 0.6em 1em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.is-dark .loop-step {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
.loop-arrow {
|
||||
font-size: 1.2rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.step-list {
|
||||
counter-reset: steps;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.step-list li {
|
||||
counter-increment: steps;
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 1.25em;
|
||||
}
|
||||
|
||||
.step-list li::before {
|
||||
content: counter(steps);
|
||||
background: var(--witch-plum);
|
||||
color: var(--witch-moon);
|
||||
border-radius: 50%;
|
||||
min-width: 1.8em;
|
||||
height: 1.8em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.9rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.is-dark .step-list li::before {
|
||||
background: var(--witch-rose);
|
||||
color: var(--witch-black);
|
||||
}
|
||||
|
||||
.mod-block {
|
||||
background: rgba(212, 165, 199, 0.08);
|
||||
border: 1px solid var(--witch-plum);
|
||||
border-radius: 10px;
|
||||
padding: 1.25em 1.5em;
|
||||
margin: 1.25em 0;
|
||||
}
|
||||
|
||||
.is-dark .mod-block {
|
||||
border-color: var(--witch-rose);
|
||||
}
|
||||
|
||||
.mod-block h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.mod-block p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
background: rgba(0, 0, 0, 0.08);
|
||||
border-radius: 4px;
|
||||
padding: 0.15em 0.4em;
|
||||
font-family: monospace;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.is-dark code {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
pre {
|
||||
background: rgba(0, 0, 0, 0.08);
|
||||
border-radius: 8px;
|
||||
padding: 1em 1.25em;
|
||||
overflow-x: auto;
|
||||
font-family: monospace;
|
||||
font-size: 0.9em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.is-dark pre {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.back-link {
|
||||
font-size: 0.9rem;
|
||||
display: block;
|
||||
margin-top: 2em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Voice AI Agent Workshop</h1>
|
||||
<div class="talk-meta">
|
||||
<span>
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
20–21 June 2026
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-map-marker-alt" aria-hidden="true"></i>
|
||||
UC Berkeley Campus, Berkeley, CA
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-user-tag" aria-hidden="true"></i>
|
||||
Speaker & Sponsor (Berkeley AI Hackathon)
|
||||
</span>
|
||||
</div>
|
||||
<div class="talk-links">
|
||||
<a href="https://ai.hackberkeley.org" target="_blank" rel="noopener noreferrer">
|
||||
<i class="fas fa-external-link-alt" aria-hidden="true"></i>
|
||||
Berkeley AI Hackathon
|
||||
</a>
|
||||
<a href="https://console.deepgram.com" target="_blank" rel="noopener noreferrer">
|
||||
<i class="fas fa-external-link-alt" aria-hidden="true"></i>
|
||||
Deepgram Console ($200 free credit)
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Voice AI is having a moment — and it's more accessible than you might think. In this
|
||||
workshop, we'll build a fully functional voice AI agent from scratch, using real-time
|
||||
speech-to-text, a large language model for reasoning, and text-to-speech to talk back. By
|
||||
the end, you'll have a working agent on your laptop that you can drop straight into a project.
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
Talk to your hackathon project in 40 minutes.
|
||||
</blockquote>
|
||||
|
||||
<p>No prior voice AI experience needed. If you've worked with an API before, you're good to go.</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<section>
|
||||
<h2>How a Voice Agent Works</h2>
|
||||
<p>
|
||||
A voice agent is three pieces wired together in a loop. Understanding this loop is the whole
|
||||
conceptual foundation. Everything else is implementation detail.
|
||||
</p>
|
||||
<div class="loop-diagram">
|
||||
<div class="loop-step">
|
||||
<strong>Ear</strong><br />
|
||||
Speech-to-Text
|
||||
</div>
|
||||
<span class="loop-arrow">→</span>
|
||||
<div class="loop-step">
|
||||
<strong>Brain</strong><br />
|
||||
LLM
|
||||
</div>
|
||||
<span class="loop-arrow">→</span>
|
||||
<div class="loop-step">
|
||||
<strong>Mouth</strong><br />
|
||||
Text-to-Speech
|
||||
</div>
|
||||
<span class="loop-arrow" style="transform: rotate(90deg); display: block;">→</span>
|
||||
</div>
|
||||
<p>
|
||||
<strong>The ear</strong> captures your audio and transcribes it in real time using
|
||||
speech-to-text. Latency here is everything: if your STT is slow, the whole agent feels
|
||||
sluggish. Deepgram's STT runs at sub-300ms end-to-end, which is fast enough to feel like
|
||||
a real conversation.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The brain</strong> receives the transcript and decides what to say. This is your
|
||||
LLM: it reasons over the conversation history and your system prompt, generates a response,
|
||||
and can call any functions you've given it access to. It can look things up, run code,
|
||||
fetch data — anything you wire in.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The mouth</strong> takes the LLM's text response and streams it back as audio. Fast
|
||||
streaming matters here too: you want audio to start playing before the full response is
|
||||
generated, or the agent feels like it's thinking too hard.
|
||||
</p>
|
||||
<p>
|
||||
With Deepgram, all three pieces run over a single WebSocket connection. You're not juggling
|
||||
three separate APIs — it's one socket, one loop, about 80 lines of code to start.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Design Decisions That Actually Matter</h2>
|
||||
<p>
|
||||
Most tutorials skip these. They're the difference between an agent that feels like a demo
|
||||
and one that feels like a tool.
|
||||
</p>
|
||||
|
||||
<h3>Interruption Handling</h3>
|
||||
<p>
|
||||
In a real conversation, you don't wait for the other person to finish before you start
|
||||
talking. Your agent shouldn't either. When the user starts speaking mid-response, the agent
|
||||
needs to stop its output and listen. Getting this wrong is the fastest way to make an agent
|
||||
feel robotic.
|
||||
</p>
|
||||
<p>
|
||||
Deepgram's Voice Agent API handles this for you. The WebSocket connection detects voice
|
||||
activity on both ends and manages the interrupt logic. You don't have to implement it
|
||||
yourself — just don't override it.
|
||||
</p>
|
||||
|
||||
<h3>Conversation State</h3>
|
||||
<p>
|
||||
Every turn in the conversation needs to be threaded correctly. The LLM needs the full
|
||||
context of what's been said so far — by both sides — to give coherent responses. This
|
||||
means maintaining a message history and passing it in with every LLM call.
|
||||
</p>
|
||||
<p>
|
||||
Keep your context window in mind. Very long conversations will eventually push older turns
|
||||
out of the context. A simple solution: keep the system prompt, the last N turns, and let
|
||||
the rest roll off. The agent won't remember everything, but the conversation will stay
|
||||
coherent.
|
||||
</p>
|
||||
|
||||
<h3>Latency</h3>
|
||||
<p>
|
||||
The number that matters is end-to-end: from when the user stops speaking to when audio
|
||||
starts playing back. Under 500ms feels conversational. Over 1 second feels like a phone
|
||||
call with bad signal.
|
||||
</p>
|
||||
<p>
|
||||
Three places latency hides: STT processing time, LLM first-token time, and TTS start time.
|
||||
Streaming helps with all three. Start playing audio as soon as the first TTS chunk arrives.
|
||||
Choose an LLM model that prioritises speed over capability for conversational use — a
|
||||
smaller, faster model is often better here than a smarter, slower one.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
|
||||
<section>
|
||||
<h2>Getting Set Up</h2>
|
||||
|
||||
<div class="callout">
|
||||
<p><strong>Before you start:</strong></p>
|
||||
<ul>
|
||||
<li>Node 20+ or Python 3.11+ installed</li>
|
||||
<li>A code editor</li>
|
||||
<li>A <a href="https://console.deepgram.com" target="_blank" rel="noopener noreferrer">free Deepgram account</a> — includes $200 credit on sign-up, no credit card needed</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p>Five steps to a running agent:</p>
|
||||
<ol class="step-list">
|
||||
<li>
|
||||
<div>
|
||||
Sign up at <a href="https://console.deepgram.com" target="_blank" rel="noopener noreferrer">console.deepgram.com</a>.
|
||||
Your account comes with $200 in free credit — more than enough for this workshop and a weekend of hacking.
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
Grab your API key from the console. It lives under API Keys in the left sidebar. Copy it somewhere safe.
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
Clone the starter repo. We'll walk through this together in the workshop, but the pattern is:
|
||||
<pre>git clone <starter-repo-url>
|
||||
cd <repo-name></pre>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
Add your API key to the environment. Create a <code>.env</code> file in the project root:
|
||||
<pre>DEEPGRAM_API_KEY=your_key_here</pre>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
Install dependencies and run it:
|
||||
<pre># Node
|
||||
npm install && npm start
|
||||
|
||||
# Python
|
||||
uv venv && uv pip install -r requirements.txt
|
||||
python main.py</pre>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
<p>
|
||||
If it's working, you'll see a connection message in the terminal and the agent will greet
|
||||
you when you speak. If it's not working, come find us at the booth.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
|
||||
<section>
|
||||
<h2>Make It Yours — Three Modifications</h2>
|
||||
<p>
|
||||
The starter app works, but it's generic. These three modifications are where the session
|
||||
becomes yours. Each one takes about five to seven minutes. Do them in order, or skip to
|
||||
whichever interests you most.
|
||||
</p>
|
||||
|
||||
<div class="mod-block">
|
||||
<h3>Modification A: Change the Personality</h3>
|
||||
<p>
|
||||
The agent's system prompt is what defines who it is. Find the <code>system_prompt</code>
|
||||
variable in the starter code — it'll look something like this:
|
||||
</p>
|
||||
<pre>system_prompt = "You are a helpful assistant."</pre>
|
||||
<p>
|
||||
Replace it with something more specific. Give the agent a name, a role, a point of view.
|
||||
For example:
|
||||
</p>
|
||||
<pre>system_prompt = """You are Alf, a friendly AI assistant at a hackathon.
|
||||
You give encouragement, suggest project ideas, and answer questions
|
||||
about voice AI. You're enthusiastic but concise - people are busy building."""</pre>
|
||||
<p>
|
||||
Restart the agent and talk to it. The change is immediate. The system prompt is the
|
||||
entire personality — there's no training, no fine-tuning. You just wrote it.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mod-block">
|
||||
<h3>Modification B: Swap the Voice</h3>
|
||||
<p>
|
||||
Deepgram's TTS has a full voice catalogue. Find the voice configuration in the starter
|
||||
code — it'll be a single string like <code>"aura-asteria-en"</code>. Change it to any
|
||||
other voice from the catalogue.
|
||||
</p>
|
||||
<p>
|
||||
A few to try:
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>aura-asteria-en</code> — warm, conversational</li>
|
||||
<li><code>aura-orion-en</code> — deep, authoritative</li>
|
||||
<li><code>aura-luna-en</code> — clear, neutral</li>
|
||||
<li><code>aura-zeus-en</code> — bold, energetic</li>
|
||||
</ul>
|
||||
<p>
|
||||
Restart and talk to your agent. It's a one-line change and the agent sounds entirely
|
||||
different. This is the modification that gets the strongest reaction.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mod-block">
|
||||
<h3>Modification C: Add a Custom Function</h3>
|
||||
<p>
|
||||
This is the one that makes you realise you can hook it to anything. Function calling lets
|
||||
the agent invoke Python (or JS) functions you write, then incorporate the result into its
|
||||
response naturally.
|
||||
</p>
|
||||
<p>
|
||||
Here's a simple example: a function that returns a random project idea when the agent
|
||||
is asked for inspiration.
|
||||
</p>
|
||||
<pre>import random
|
||||
|
||||
def get_project_idea():
|
||||
ideas = [
|
||||
"A voice-controlled to-do list that reads back your tasks",
|
||||
"An AI study buddy that quizzes you out loud",
|
||||
"A real-time translator that speaks back in the target language",
|
||||
"A voice journalling app that summarises your entries",
|
||||
]
|
||||
return random.choice(ideas)</pre>
|
||||
<p>
|
||||
Register this function with the agent and tell the LLM when to use it via the system
|
||||
prompt: <em>"When asked for a project idea, call get_project_idea() and share the result."</em>
|
||||
</p>
|
||||
<p>
|
||||
Now ask your agent for a project idea. Watch it call the function and weave the result
|
||||
into a natural spoken response. This is the "aha" moment: the agent can call your own
|
||||
code, your own APIs, your own data. The voice interface is just the front door.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
|
||||
<section>
|
||||
<h2>What You Can Build From Here</h2>
|
||||
<p>
|
||||
Now that you have a working, personalised, function-capable voice agent, here's what that
|
||||
unlocks for your hackathon project:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Accessibility layer</strong> — add voice input and output to any existing
|
||||
interface. Users who can't type or read small text get a completely different experience.
|
||||
</li>
|
||||
<li>
|
||||
<strong>In-game NPC</strong> — drop the agent into a game as a character that actually
|
||||
talks back. Hook the function calling to your game state so it knows what's happening.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Voice-controlled developer tool</strong> — talk to your build process, your
|
||||
deploy pipeline, your monitoring dashboard. Voice is an unusually good interface for
|
||||
things you want to do hands-free.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Multilingual support</strong> — Deepgram's STT handles dozens of languages.
|
||||
The LLM can respond in whatever language the user speaks. Global voice interface, almost for free.
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Get Help</h2>
|
||||
<p>Building something? Stuck on something? Here's where to find us:</p>
|
||||
<ul>
|
||||
<li><strong>At the event:</strong> the Deepgram booth — we're here all weekend</li>
|
||||
<li><strong>Docs:</strong> <a href="https://developers.deepgram.com" target="_blank" rel="noopener noreferrer">developers.deepgram.com</a></li>
|
||||
<li><strong>Community:</strong> <a href="https://deepgram.com/discord" target="_blank" rel="noopener noreferrer">Deepgram's Discord</a></li>
|
||||
</ul>
|
||||
<p>
|
||||
The Deepgram challenge prize this weekend goes to the team that builds the most creative
|
||||
voice-powered experience. Come say hi, show us what you're building, and let us know if you
|
||||
want feedback on your voice integration before judging.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
<a class="back-link" href="/">
|
||||
<i class="fas fa-arrow-left" aria-hidden="true"></i>
|
||||
Back to all talks
|
||||
</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
+1215
File diff suppressed because it is too large
Load Diff
+156
-6
@@ -57,6 +57,89 @@
|
||||
<p>Want to submit your own? <a href="https://forms.nhcarrigan.com/form/M_GrmqASymmO744axMOmu2LaMAaT5F0LmdVcU2c8-gQ">Use our web form</a>.</p>
|
||||
<section>
|
||||
|
||||
<div class="card">
|
||||
<p class="title">Frances (paraphrased from dm)</p>
|
||||
<p>I have seen how much constant work you've done; all the kindness, inspiration, and positive energy you've poured into each of us through the years. The online world can be so cold, fake, and uncaring, but I feel your graciousness, warmth, and tenderness through your constancy, words, and patience. Thank you, basically, for being you. You've been a constant example of doing good work.</p>
|
||||
<p class="date">18 April 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">TR</p>
|
||||
<p>OMG Naomi is *thee* GOAT Discord Community Creater. My name is TR (tEE ARe) and I came by here by way of FreeCodeCamp server.... which is the only Learning-based community on discord that actually knows how to use Discord. At that is All Naomi's doing. And on top of that She has has the **monster-shoe** 👠 of blinged out Profiles, and this Server to boot . Way impressed. 🙏 plz teach me 0--venerable guru!❣️</p>
|
||||
<p class="date">2 April 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Rain</p>
|
||||
<p>Happy Trans Day, Naomi 🏳️⚧️🤍
|
||||
|
||||
I love you so much. You're a true blessing, and I hope you know how amazing you are.
|
||||
|
||||
This server means a lot to so many people. I've heard from others how safe they feel here…something they don't always experience in other spaces. That's because of the environment you've created.
|
||||
|
||||
You're a great inspiration to many developers finding their place in this world. Seeing a trans woman thrive in a male-dominated space is incredibly powerful. Your presence alone is motivating.</p>
|
||||
<p class="date">1 April 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">minjo70</p>
|
||||
<p>Praise be to you Great One! Our incredible Naomi, who we adore all moments of our time awake. And in our dreams may you persist with sweet laughter and joy. Your chaos, your memory live in our souls.</p>
|
||||
<p class="date">31 March 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Velo</p>
|
||||
<p>Proud to be part of this community—thank you, Naomi, for everything you do</p>
|
||||
<p class="date">31 March 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">roseaboveit</p>
|
||||
<p>Especially in a learning space what is most important actually is the modeling you do for the learning environment you are cultivating. In this case when you overdo it modeling how to step back and recalibrate with the community and during that recalibration evaluate your systems to provide buffer for yourself to decrease the odds that future recalibrations will be necessary. People going above and beyond is how workers get exploited and in learning spaces it is good to model the tools folks need to be able to represent themselves and fight for their own needs in a world where people will be constantly pushing for more.
|
||||
|
||||
Thanks Naomi for all that you do. Everything will be fine. People have a bunch of free resources available to them while you recalibrate and there are plenty of additional places they can get supplementation if that is required and they can't wait. It is good leadership to say no to things that are unsustainable.</p>
|
||||
<p class="date">26 March 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Wildfire</p>
|
||||
<p>I may not know you and you may not know me, but I am very glad you're still here ❤️ you are light to many people in this server!</p>
|
||||
<p class="date">17 March 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Anny</p>
|
||||
<p>I hate being at war. it makes international womens day harder to feel like celebrating. being stuck in a bomb shelter sucks... but at least i get some time to study work towards finding a place in tech as a developer. Mama Naomi, you are so right about how far we've come, and how far we still have to go.</p>
|
||||
<p class="date">8 March 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">blairingmysoul.bsky.social</p>
|
||||
<p>I'm glad so many others appreciate the community you've built.👏💖</p>
|
||||
<p class="date">4 March 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Internal Feedback (Anonymised for privacy)</p>
|
||||
<p>I just finished reading the report. Excellent work, Naomi. This seems to reinforce our instincts that we just want Socrates to give feedback on code, and we want to position it as a tool that helps you get unstuck without risking learned helplessness or backsliding on your skills.</p>
|
||||
<p class="date">26 February 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Wildfire</p>
|
||||
<p>I know, you were kind to me a while ago, you gave me the confidence to share my project in this community, which I did. Because of your kind words to me. 💜</p>
|
||||
<p class="date">25 February 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Internal Feedback (Anonymised for privacy)</p>
|
||||
<p>Thanks Naomi. Firstly, keep up the good work on the spring cohort. It has been amazing to see contributions and meaningful engagement from first-timers. No one gets that done better than you!</p>
|
||||
<p class="date">20 February 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Quincy Larson</p>
|
||||
<p>Naomi is extremely good at finding opportunities to improve our platform and our community that nobody has even thought of. She's also adept at explaining those ideas, implementing them, and rallying other team members to help her making them a reality. She's a massive asset to the freeCodeCamp community and to our charity's developer staff.</p>
|
||||
<p class="date">10 February 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Internal Feedback (Anonymised for privacy)</p>
|
||||
<p>Kudos Naomi for picking it up while I was out sick thank you ❤️</p>
|
||||
<p class="date">17 January 2026</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Isaac</p>
|
||||
<p>I would like to shout out Naomi. Lowkey, she carries a lot of work here. She took time to organize events for online, she's constantly offering help to everyone, her bots are actively used in the server. And beyond what she does for us, she's always ready to stand up for anyone who she feels she needs to. Naomi, you are an amazing human being! We are grateful to have you in this community</p>
|
||||
<p class="date">19 December 2025</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Hanna Rose</p>
|
||||
<p>Naomi is an extremely hard working individual who knows no bounds but her own. She constantly pushes herself and her team to do they best they can and ensures the results she delivers is as high quality as possible. With resilient determination and outstanding coordination and leadership skills, there is no one else that could even remotely match her level of talent.</p>
|
||||
@@ -72,6 +155,11 @@
|
||||
<p>Naomi and a colleague rotated dozens and dozens and dozens of credentials while ensuring as many tools as possible could stay functional through the holiday weekend. They used their deep knowledge of version control systems to recommend paths forward, and proactively thought of additional ways we can increase security within our repos. Naomi and her colleague were also on the call Wednesday night for hours and went on to complete many, many tasks throughout the long weekend. Kudos to Naomi and colleagues for diligently combing through our repos and undoing the erroneous changes.</p>
|
||||
<p class="date">1 December 2025</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Internal Feedback (Anonymised for privacy)</p>
|
||||
<p>Naomi hustled this weekend and churned out a working SDK that supports a new platform integration, and documentation too! Let's give a round of applause for the teamwork!</p>
|
||||
<p class="date">24 November 2025</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Internal Feedback (Anonymised for privacy)</p>
|
||||
<p>We've had a lot of help along the way, including the tireless work colleagues like Naomi have put into making this happen, plus short-order efforts from engineering teams (including Naomi) to get our SDKs ready for this product launch.</p>
|
||||
@@ -102,11 +190,6 @@
|
||||
<p>I wanted to give a shout out to Naomi who is always so patient when I ask her about complex GIT situations I "git" myself into. Whether it's a funky rebase or major merge conflicts she always has the answers and is soooo helpful.</p>
|
||||
<p class="date">26 September 2025</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Internal Feedback (Anonymised for privacy)</p>
|
||||
<p>I wanted to give a shout out to Naomi who is always so patient when I ask her about complex GIT situations I "git" myself into. Whether it's a funky rebase or major merge conflicts she always has the answers and is so helpful.</p>
|
||||
<p class="date">26 September 2025</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Internal Feedback (Anonymised for privacy)</p>
|
||||
<p>Kudos to Naomi for all of the initiatives on Discord. The community is really thriving and it is bringing more engagement to the organization!</p>
|
||||
@@ -178,7 +261,7 @@
|
||||
<p class="date">14 August 2025</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Nielda Karlo Melo</p>
|
||||
<p class="title">Nielda Karla Melo</p>
|
||||
<p>Naomi is one of the most competent professionals I have had the pleasure of working with. She has an exceptional presence, giving the impression of being everywhere at once, and her attention to detail is remarkable. She is able to identify subtle points and gaps in reasoning that others might miss and point that out in a respectful way. Naomi is not one to avoid difficult conversations. She expresses her opinions with clarity, confidence, and thoughtfulness. Her work on freeCodeCamp’s Discord, in addition to the many other code-related contributions she has made, is nothing short of impressive. She has kept the community engaged, planned events that people genuinely want to attend, and led the management of the entire space. Thanks to her leadership, the community has become a respectful, welcoming, and valuable place to be a part of. Any team would be fortunate to have Naomi’s expertise, dedication, and leadership.</p>
|
||||
<p class="date">14 August 2025</p>
|
||||
</div>
|
||||
@@ -192,11 +275,21 @@
|
||||
<p>Quick shout out to a colleague and Naomi today for a late night hot fix and lighting fast review (7 mins!) for our NodeJS SDK to get audio streaming working with the latest React (5+). Release - v4.9.1 updates our webpack support for modern JS bundlers (Vite, React App v5+, Next.js) to fix streaming audio through the browser. This helped unblock an important prospect that would impact other important buyers in that market. Great bias for action, and tight teamwork all around, bravo!</p>
|
||||
<p class="date">9 July 2025</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">jake-haver-of-catz.bsky.social</p>
|
||||
<p>This morning I had my mind melted with a run through of @github.com by freeCodeCamp super champion, Naomi! Super grateful for this workshop to get our feet wet before we need to use this to collaborate on our projects in a few days! AH! Day 219/365 #code365 #goOnGit #100devs #freeCodeCamp</p>
|
||||
<p class="date">30 June 2025</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Internal Feedback (Anonymised for privacy)</p>
|
||||
<p>I want to give BIG kudos to Naomi and colleagues for their strength, bravery and love they shared with all of us today! What a tremendous presentation full of passion, information and dedication!</p>
|
||||
<p class="date">26 June 2025</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">paddle</p>
|
||||
<p>Thanks for the update! It sounds like you've put a lot of effort into enhancing our Discord community. The events you mentioned, especially the mentorship sessions and accountability calls, sound like great opportunities for everyone to connect and improve their skills. I think the feedback channel is a fantastic idea, too. It'll be really helpful for gathering ideas directly from members. I'm looking forward to seeing how these changes will make our community even more engaging. Keep up the great work!</p>
|
||||
<p class="date">24 May 2025</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Internal Feedback (Anonymised for privacy)</p>
|
||||
<p>I want to give some big Kudos to Naomi and a colleague for all the great developer experience work they did last week while many of us were travelling. Naomi pushed forward with internal chatbot development, which is a company-centric Slack Bot that uses our knowledge base to answer questions. This bot is available in our current Slack Workspace now! Long Term we want to make it available to our customers to install in their own workspaces so they can get their questions answered quickly. It will eventually be Voice Enabled using our Voice API, which means customers would authenticate and make API requests to use Voice features</p>
|
||||
@@ -277,6 +370,11 @@
|
||||
<p>Naomi is an absolute trailblazer, and is an amazing person to work with! Naomi is humorous and also has an amazing attitude to work with. Her ability to solve complex problems efficiently astounds me. Not only does she demonstrate outstanding technical knowledge, but also does an amazing job at elucidating her needs as an engineer. She is a very warm person and quite easy to work with. Naomi is immensely perceptive and very calculated with what she does. Naomi would make an excellent addition to any company that is lucky enough to hire her!</p>
|
||||
<p class="date">2 May 2024</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">plamoni</p>
|
||||
<p>Note that Naomi has been coding for like 3 years now. I've been coding for 30 years and have nothing public that's anywhere near as good as this project. So realize that Naomi is a bit of an outlier with this and you shouldn't feel like you have to hit this bar to be successful. 🙂</p>
|
||||
<p class="date">30 September 2023</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Danny Thompson</p>
|
||||
<p>If you need a problem solver, look at Naomi. Naomi is a fantastic part of the online tech community by teaching and offering help to beginners on their journeys into tech. She has created some great solutions and is a consistent learner. Naomi has led initiatives using Javascript and front-end technologies to produce finished products within a volunteer position. Highly recommend Naomi to any team.</p>
|
||||
@@ -286,6 +384,58 @@
|
||||
<p class="title">Eddie Jaoude</p>
|
||||
<p>Naomi has done a fantastic job in creating Becca Bot, which is an integral part in managing the EddieHub Discord Community. As founder of EddieHub, Naomi is super helpful to all Community members and an excellent moderator, from our text channels to audio calls and live streams. Naomi demonstrates an excellent technical knowledge and is always keen to share this with the community.</p>
|
||||
<p class="date">30 June 2023</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">blackpug</p>
|
||||
<p>Wow, that is an incredible explanation [of a complex regex concept], thank you so much for taking the time to explain it in so much detail. I learned so much from the answer you provided. This is brilliant.</p>
|
||||
<p class="date">25 April 2023</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">BigBonBon</p>
|
||||
<p>Shout out to Naomi for making it feel less daunting to talk/engage with people over discord.</p>
|
||||
<p class="date">29 August 2022</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Luke Oliff</p>
|
||||
<p>Naomi is a career switching ~~future~~ open source star. When I first met Naomi she was still looking for her first full-time tech role, and now she is an engineer for one of the most important free spaces for folks looking to get into tech, freeCodeCamp. Follow for great takes, great content, and great open source projects!</p>
|
||||
<p class="date">8 March 2022</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">plamoni</p>
|
||||
<p>Notably, Naomi is a bit of a rock-star with this stuff. She is clearly keeping a ton of plates spinning and getting a lot done. It's hard *not* to notice it.
|
||||
|
||||
If you can be 50% as engaged as she is, you'll be absolutely fine. 😄</p>
|
||||
<p class="date">2 March 2022</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">GDG Memphis</p>
|
||||
<p>[Naomi Carrigan] is a developer at freeCodeCamp. Primarily working in TypeScript, she has built CLI tools, curriculum content, APIs, and Discord bots. She is very passionate about open source and community building, and has helped shape and guide multiple OSS communities and developers.</p>
|
||||
<p class="date">21 September 2021</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">manuarora</p>
|
||||
<p>Today I wrote my first blog for freeCodeCamp publication. I'm thankful to you for letting me know that I could do something like this.</p>
|
||||
<p class="date">18 August 2021</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">procz</p>
|
||||
<p>hey! just wanted to take a minute to thank Naomi, and probably some other people i'm forgetting, as well as freeCodeCamp in general, for all the help in the past few months, finally got my first job in the industry and your help really made it easier 🙂</p>
|
||||
<p class="date">9 April 2021</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">Jessica Wilkins</p>
|
||||
<p>I decided to reach out to [Naomi Carrigan] who is a freeCodeCamp developer and moderator. She had a service for code review sessions on her website and I wanted her to take a look at my code. The code review session was very valuable and I learned a lot about how to make the site even better.</p>
|
||||
<p class="date">3 February 2021</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">lilykhan</p>
|
||||
<p>[In a year-end reflection on learning to code:] A few amazing people who made this year amazing and to whom I'm so thankful for — [including Naomi]. They never said I'm not good enough, and they all encourage me to try out new stuff and to give my best shot. They trust in me even when I don't trust in myself.</p>
|
||||
<p class="date">31 December 2020</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<p class="title">codeofdreams</p>
|
||||
<p>[While seeking help debugging a JavaScript project:] I would appreciate your assistance and input. You are my favorite moderator. Thank you!</p>
|
||||
<p class="date">12 August 2020</p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user