generated from nhcarrigan/template
Compare commits
25 Commits
07aa12a042
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
e743c8f224
|
|||
|
54aa95db64
|
|||
|
066ff0d649
|
|||
|
4637711381
|
|||
|
73f829f5d4
|
|||
|
3b40c97d8e
|
|||
| 7fc742d199 | |||
| 30415c5e7e | |||
|
d0c38ab520
|
|||
| 6109ec3183 | |||
| 59e2f53cfa | |||
| faa553b42d | |||
|
6083564185
|
|||
|
d108ddecd5
|
|||
| b0315e6e18 | |||
| 9c5cae2812 | |||
| 6a4dd72384 | |||
| 6236029975 | |||
| 573a9f9b1e | |||
| 1aa7583f51 | |||
| 739119b72a | |||
| 5e933826c3 | |||
|
c66409fe86
|
|||
|
85f80fb159
|
|||
|
bbac528845
|
+17
-5
@@ -8,22 +8,31 @@ on:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint and Test
|
||||
ci:
|
||||
name: CI
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Source Files
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Use Node.js v22
|
||||
- name: Use Node.js v24
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 9
|
||||
version: 10
|
||||
|
||||
- name: Ensure Dependencies are Pinned
|
||||
uses: naomi-lgbt/dependency-pin-check@main
|
||||
with:
|
||||
language: javascript
|
||||
dev-dependencies: true
|
||||
peer-dependencies: true
|
||||
optional-dependencies: true
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
@@ -36,3 +45,6 @@ jobs:
|
||||
|
||||
- name: Run Tests
|
||||
run: pnpm run test
|
||||
|
||||
- name: Run Spellcheck
|
||||
run: pnpm run spellcheck
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
name: Security Scan and Upload
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '0 0 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
security-audit:
|
||||
name: Security & DefectDojo Upload
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# --- AUTO-SETUP PROJECT ---
|
||||
- name: Ensure DefectDojo Product Exists
|
||||
env:
|
||||
DD_URL: ${{ secrets.DD_URL }}
|
||||
DD_TOKEN: ${{ secrets.DD_TOKEN }}
|
||||
PRODUCT_NAME: ${{ github.repository }}
|
||||
PRODUCT_TYPE_ID: 1
|
||||
run: |
|
||||
sudo apt-get install jq -y > /dev/null
|
||||
|
||||
echo "Checking connection to $DD_URL..."
|
||||
|
||||
# Check if product exists - capture HTTP code to debug connection issues
|
||||
RESPONSE=$(curl --write-out "%{http_code}" --silent --output /tmp/response.json \
|
||||
-H "Authorization: Token $DD_TOKEN" \
|
||||
"$DD_URL/api/v2/products/?name=$PRODUCT_NAME")
|
||||
|
||||
# If response is not 200, print error
|
||||
if [ "$RESPONSE" != "200" ]; then
|
||||
echo "::error::Failed to query DefectDojo. HTTP Code: $RESPONSE"
|
||||
cat /tmp/response.json
|
||||
exit 1
|
||||
fi
|
||||
|
||||
COUNT=$(cat /tmp/response.json | jq -r '.count')
|
||||
|
||||
if [ "$COUNT" = "0" ]; then
|
||||
echo "Creating product '$PRODUCT_NAME'..."
|
||||
curl -s -X POST "$DD_URL/api/v2/products/" \
|
||||
-H "Authorization: Token $DD_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "name": "'"$PRODUCT_NAME"'", "description": "Auto-created by Gitea Actions", "prod_type": '$PRODUCT_TYPE_ID' }'
|
||||
else
|
||||
echo "Product '$PRODUCT_NAME' already exists."
|
||||
fi
|
||||
|
||||
# --- 1. TRIVY (Dependencies & Misconfig) ---
|
||||
- name: Install Trivy
|
||||
run: |
|
||||
sudo apt-get install wget apt-transport-https gnupg lsb-release -y
|
||||
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
|
||||
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
|
||||
sudo apt-get update && sudo apt-get install trivy -y
|
||||
|
||||
- name: Run Trivy (FS Scan)
|
||||
run: |
|
||||
trivy fs . --scanners vuln,misconfig --format json --output trivy-results.json --exit-code 0
|
||||
|
||||
- name: Upload Trivy to DefectDojo
|
||||
env:
|
||||
DD_URL: ${{ secrets.DD_URL }}
|
||||
DD_TOKEN: ${{ secrets.DD_TOKEN }}
|
||||
run: |
|
||||
echo "Uploading Trivy results..."
|
||||
# Generate today's date in YYYY-MM-DD format
|
||||
TODAY=$(date +%Y-%m-%d)
|
||||
|
||||
HTTP_CODE=$(curl --write-out "%{http_code}" --output response.txt --silent -X POST "$DD_URL/api/v2/import-scan/" \
|
||||
-H "Authorization: Token $DD_TOKEN" \
|
||||
-F "active=true" \
|
||||
-F "verified=true" \
|
||||
-F "scan_type=Trivy Scan" \
|
||||
-F "engagement_name=CI/CD Pipeline" \
|
||||
-F "product_name=${{ github.repository }}" \
|
||||
-F "scan_date=$TODAY" \
|
||||
-F "auto_create_context=true" \
|
||||
-F "file=@trivy-results.json")
|
||||
|
||||
if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then
|
||||
echo "::error::Upload Failed with HTTP $HTTP_CODE"
|
||||
echo "--- SERVER RESPONSE ---"
|
||||
cat response.txt
|
||||
echo "-----------------------"
|
||||
exit 1
|
||||
else
|
||||
echo "Upload Success!"
|
||||
fi
|
||||
|
||||
# --- 2. GITLEAKS (Secrets) ---
|
||||
- name: Install Gitleaks
|
||||
run: |
|
||||
wget -qO gitleaks.tar.gz https://github.com/gitleaks/gitleaks/releases/download/v8.18.0/gitleaks_8.18.0_linux_x64.tar.gz
|
||||
tar -xzf gitleaks.tar.gz
|
||||
sudo mv gitleaks /usr/local/bin/ && chmod +x /usr/local/bin/gitleaks
|
||||
|
||||
- name: Run Gitleaks
|
||||
run: gitleaks detect --source . -v --report-path gitleaks-results.json --report-format json --no-git || true
|
||||
|
||||
- name: Upload Gitleaks to DefectDojo
|
||||
env:
|
||||
DD_URL: ${{ secrets.DD_URL }}
|
||||
DD_TOKEN: ${{ secrets.DD_TOKEN }}
|
||||
run: |
|
||||
echo "Uploading Gitleaks results..."
|
||||
TODAY=$(date +%Y-%m-%d)
|
||||
|
||||
HTTP_CODE=$(curl --write-out "%{http_code}" --output response.txt --silent -X POST "$DD_URL/api/v2/import-scan/" \
|
||||
-H "Authorization: Token $DD_TOKEN" \
|
||||
-F "active=true" \
|
||||
-F "verified=true" \
|
||||
-F "scan_type=Gitleaks Scan" \
|
||||
-F "engagement_name=CI/CD Pipeline" \
|
||||
-F "product_name=${{ github.repository }}" \
|
||||
-F "scan_date=$TODAY" \
|
||||
-F "auto_create_context=true" \
|
||||
-F "file=@gitleaks-results.json")
|
||||
|
||||
if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then
|
||||
echo "::error::Upload Failed with HTTP $HTTP_CODE"
|
||||
echo "--- SERVER RESPONSE ---"
|
||||
cat response.txt
|
||||
echo "-----------------------"
|
||||
exit 1
|
||||
else
|
||||
echo "Upload Success!"
|
||||
fi
|
||||
|
||||
# --- 3. SEMGREP (SAST) ---
|
||||
- name: Install Semgrep (via pipx)
|
||||
run: |
|
||||
sudo apt-get install pipx -y
|
||||
pipx install semgrep
|
||||
# Add pipx binary path to GITHUB_PATH so next steps can see 'semgrep'
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Run Semgrep
|
||||
run: semgrep scan --config=p/security-audit --config=p/owasp-top-ten --json --output semgrep-results.json . || true
|
||||
|
||||
- name: Upload Semgrep to DefectDojo
|
||||
env:
|
||||
DD_URL: ${{ secrets.DD_URL }}
|
||||
DD_TOKEN: ${{ secrets.DD_TOKEN }}
|
||||
run: |
|
||||
echo "Uploading Semgrep results..."
|
||||
TODAY=$(date +%Y-%m-%d)
|
||||
|
||||
HTTP_CODE=$(curl --write-out "%{http_code}" --output response.txt --silent -X POST "$DD_URL/api/v2/import-scan/" \
|
||||
-H "Authorization: Token $DD_TOKEN" \
|
||||
-F "active=true" \
|
||||
-F "verified=true" \
|
||||
-F "scan_type=Semgrep JSON Report" \
|
||||
-F "engagement_name=CI/CD Pipeline" \
|
||||
-F "product_name=${{ github.repository }}" \
|
||||
-F "scan_date=$TODAY" \
|
||||
-F "auto_create_context=true" \
|
||||
-F "file=@semgrep-results.json")
|
||||
|
||||
if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then
|
||||
echo "::error::Upload Failed with HTTP $HTTP_CODE"
|
||||
echo "--- SERVER RESPONSE ---"
|
||||
cat response.txt
|
||||
echo "-----------------------"
|
||||
exit 1
|
||||
else
|
||||
echo "Upload Success!"
|
||||
fi
|
||||
@@ -0,0 +1,3 @@
|
||||
# dunno why i needed this but the vscode extension complained so here it is
|
||||
# a nice empty file with no purpose
|
||||
# kinda like naomi~
|
||||
Vendored
+8
-1
@@ -2,5 +2,12 @@
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"eslint.validate": ["typescript"],
|
||||
"eslint.validate": [
|
||||
"typescript"
|
||||
],
|
||||
"cSpell.words": [
|
||||
],
|
||||
"cSpell.dictionaryDefinitions": [
|
||||
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,36 +1,29 @@
|
||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
# blog
|
||||
|
||||
## Getting Started
|
||||
Naomi's personal blog.
|
||||
|
||||
First, run the development server:
|
||||
## Live Version
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
This page is currently deployed. [View the live website.](https://blog.nhcarrigan.com)
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
## Feedback and Bugs
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
If you have feedback or a bug report, please [log a ticket on our forum](https://support.nhcarrigan.com).
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||
## Contributing
|
||||
|
||||
## Learn More
|
||||
If you would like to contribute to the project, you may create a Pull Request containing your proposed changes and we will review it as soon as we are able! Please review our [contributing guidelines](CONTRIBUTING.md) first.
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
## Code of Conduct
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
Before interacting with our community, please read our [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
## License
|
||||
|
||||
## Deploy on Vercel
|
||||
This software is licensed under our [global software license](https://docs.nhcarrigan.com/#/license).
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
Copyright held by Naomi Carrigan.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
## Contact
|
||||
|
||||
We may be contacted through our [Chat Server](http://chat.nhcarrigan.com) or via email at `contact@nhcarrigan.com`
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"language": "en-GB",
|
||||
"allowCompoundWords": true,
|
||||
"dictionaries": [
|
||||
"en-gb",
|
||||
"companies",
|
||||
"softwareTerms",
|
||||
"typescript",
|
||||
"node",
|
||||
"html",
|
||||
"css",
|
||||
"bash"
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
"```[\\s\\S]*?```", // Ignores multi-line code blocks in Markdown
|
||||
"`[^`\n]+`" // Ignores inline code blocks
|
||||
],
|
||||
"words": [
|
||||
"corpo",
|
||||
"Cthulu's",
|
||||
"debaucherous",
|
||||
"Faer",
|
||||
"Fenrir",
|
||||
"Fortnite",
|
||||
"Gitea",
|
||||
"Hatsune",
|
||||
"Hikari",
|
||||
"LGBTQ",
|
||||
"Lich",
|
||||
"Migadu",
|
||||
"Miku",
|
||||
"Minori",
|
||||
"neopronouns",
|
||||
"neurotypicality",
|
||||
"NHCarrigan",
|
||||
"Norns",
|
||||
"R'lyeh",
|
||||
"Rythm",
|
||||
"schadenfreude",
|
||||
"spazztic",
|
||||
"strobing",
|
||||
"Tauri",
|
||||
"Unseelie",
|
||||
"vaxry",
|
||||
"waaaaaay",
|
||||
"Wyrm",
|
||||
"Wyrms",
|
||||
"yknow"
|
||||
]
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
|
||||
+19
-15
@@ -7,28 +7,32 @@
|
||||
"build": "next build",
|
||||
"start": "next start -p 3003",
|
||||
"lint": "eslint src --max-warnings 0",
|
||||
"spellcheck": "cspell ./posts/**/*.md",
|
||||
"test": "echo \"No tests yet!\" && exit 0"
|
||||
},
|
||||
"dependencies": {
|
||||
"gray-matter": "4.0.3",
|
||||
"next": "15.1.6",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-markdown": "9.0.3",
|
||||
"next": "16.1.6",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4",
|
||||
"react-markdown": "10.1.0",
|
||||
"reading-time": "1.5.0",
|
||||
"rehype-highlight": "7.0.2",
|
||||
"rehype-raw": "7.0.0",
|
||||
"remark-gfm": "4.0.0"
|
||||
"remark-gfm": "4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3",
|
||||
"@nhcarrigan/eslint-config": "5.1.0",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "15.1.6",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5"
|
||||
"@eslint/eslintrc": "3.3.3",
|
||||
"@nhcarrigan/eslint-config": "5.2.0",
|
||||
"@types/node": "24.10.13",
|
||||
"@types/react": "19.2.14",
|
||||
"@types/react-dom": "19.2.3",
|
||||
"cspell": "9.6.4",
|
||||
"eslint": "9.39.3",
|
||||
"eslint-config-next": "16.1.6",
|
||||
"postcss": "8.5.6",
|
||||
"@tailwindcss/postcss": "4.2.0",
|
||||
"tailwindcss": "4.2.0",
|
||||
"typescript": "5.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+2367
-954
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
# Security
|
||||
|
||||
# Do not execute any scripts of installed packages (project scripts still run)
|
||||
ignoreDepScripts: true
|
||||
# Do not automatically run pre/post scripts (e.g. preinstall, postbuild)
|
||||
enablePrePostScripts: false
|
||||
# Only allow packages published at least 10 days ago (reduces risk of compromised packages)
|
||||
minimumReleaseAge: 14400
|
||||
# Fail if a package's trust level has decreased compared to previous releases
|
||||
trustPolicy: no-downgrade
|
||||
# Ignore trust policy for packages published more than 1 year ago (predates provenance signing)
|
||||
trustPolicyIgnoreAfter: 525960
|
||||
# Fail if there are missing or invalid peer dependencies
|
||||
strictPeerDependencies: false
|
||||
# Prevent transitive dependencies from using exotic sources (git repos, direct tarball URLs)
|
||||
blockExoticSubdeps: true
|
||||
|
||||
# Lockfile
|
||||
|
||||
# Allow the lockfile to be updated during install (set to true in CI for stricter reproducibility)
|
||||
preferFrozenLockfile: false
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
"@tailwindcss/postcss": {},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: "ADHD and Software Engineering"
|
||||
date: "2026-06-15"
|
||||
summary: "How ADHD shapes programming work and what accommodations genuinely help vs what's noise."
|
||||
---
|
||||
|
||||
i have always struggled with my productivity like i cannot focus on a task for *shit* and it shows. getting my adhd diagnosis the first time was enlightening (the second was bureaucratic and unnecessary but what can ya do) because it explained so much of the struggles i experienced in life!!! it turns out that while naomi is indeed lazy it is not as bad as one might think because half of it is just my adhd sending me to a different topic~
|
||||
|
||||
like i can hyperfocus and crank out work for sixteen hours straight one day and get distracted by every single slack message the next. it's not a lack of motivation or a problem with self-discipline. its adhd.
|
||||
|
||||
so lets talk about what adhd actually *does* to this software engineer. no stereotypes, no fluff. just one girl's honest account.
|
||||
|
||||
hyperfixation can certainly *seem* like a blessing and in many ways it is!!!! like i found my success because i hyperfixated on learning to code during a time when i had fuck all else to do!!!! but i also did not *choose* to hyperfixate - my brain chose for me~
|
||||
|
||||
and its a curse too. i can hyperfocus on a task for six hours, get it done, and then spend the next *four* working up the motivation to do another task. starting a task is a monumental endeavour. context switching is a nightmare.
|
||||
|
||||
and like a *lot* of the productivity hacks that a neurobland engineer might use are totally useless for me. pomodoro? more like interruption hell. get the hardest task done first? **starting a task is the hardest task** how am i supposed to do that hm???? constant slack and discord and email inputs? just more distractions, albeit important ones!
|
||||
|
||||
here's what actually helps! give me my music playlist, a quiet comfy corner, a mug of coffee or tea or cider, and 16 hours of uninterrupted time? i can change your entire company. let me wrap up a thing before moving on to the next - if i have walked away for too long i will never pick it back up and this is why i don't finish video games!!!! solid task and note software like omg asana and notion *are* my brain lately.
|
||||
|
||||
of course hikari helps too~
|
||||
|
||||
software engineering is in some ways *very good* for the adhd brain and in other ways it is a total nightmare. let me sink into a idea-test-refine loop and i can crank out some really cool shit. give me vague directionless assignments and you might get a lump of clay in return. code reviews??? nah fam if it is more than like 10 lines of code i simply will not read it. i cannot bring myself to do it. it does not satisfy the demons in my head.
|
||||
|
||||
medication helps a lot. provided your psychiatrist isnt withholding them. mine is, for safety reasons (apparently they make mood swings worse). now i am barely functioning. working in an environment that allows for fluctuations in productivity, when the net positive is high, is absolutely vital. like i can deliver anything you need me to!!!!!! you'll just get total silence for a week and then 50 updates in a day and then another week of silence and then here's an app~
|
||||
|
||||
remote work helps. a lot. i get my quiet office in my very expensive comfy chair and no one bothers me and i can vibe to my music and kick ass and take names. but with no one there to keep me on track, a rabbit hole can be the death of the workday.
|
||||
|
||||
none of this is medical advice. im not legally allowed to give you medical advice. if you take this blog post as medical advice, i am curious what about me gives you *any* idea that i am a credible source of information. i literally just rambled on for 4000 characters about how chaotic i am.
|
||||
|
||||
but this *is* real. this *is* my real experience. this *is* my every day. this *is* adhd. this *is* naomi~ đź©·
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
title: "AI Art, Ethics, and the Dopamine Tax"
|
||||
date: "2026-04-02"
|
||||
summary: "An honest reckoning with my one vice, why I can't quit it, and whether the good I try to put into the world counts for anything."
|
||||
---
|
||||
|
||||
Okay so. I've written before about [where I stand on AI ethics](/post/ai-bigots-and-media), and I'm not going to walk any of that back. Data sourced without artist consent. Environmental costs. Underpaid labellers doing genuinely traumatic work. I believe all of that. I believe it *deeply*.
|
||||
|
||||
But I use AI to generate images of myself. And I want to be honest about why.
|
||||
|
||||
## The Dopamine Problem
|
||||
|
||||
[I've written about my brain before.](/post/living-with-mental-illness) ADHD. Depression. Schizophrenia. A handful of other things that all interact in fun and exciting ways. The short version: my brain has a *broken* relationship with dopamine.
|
||||
|
||||
The reward signals other people get for free? I don't get those. The small glow of finishing something. The warm buzz of a nice afternoon. Simple joy. My brain charges me extra for all of it. Constantly.
|
||||
|
||||
But there's another layer I haven't talked about as publicly: I have a BPD diagnosis. And one of the things that comes with that is that emotions don't land at normal intensity for me. They land at about 10x. Negative things feel catastrophic. But positive things? When they're *good*, they're *really* good. Like, genuinely euphoric. Joy doesn't arrive quietly for me, it arrives like a wave.
|
||||
|
||||
So when I find something that reliably produces genuine happiness? That matters. That matters a lot.
|
||||
|
||||
> Finding a reliable source of joy, when your brain chemistry makes joy genuinely hard to come by, is not a small thing.
|
||||
|
||||
What I've found is what my friends and I call "Naomi art." Images of a character that looks like me. Wavy brown hair, blue eyes, fangs, always barefoot. Rendered in an art style I love. There is something specifically and powerfully good about seeing yourself depicted beautifully. Not in a photograph. Not in a mirror. In *art*.
|
||||
|
||||
I am a transgender woman. I spent a long time not seeing myself clearly, or seeing myself in ways that didn't match how I understood myself at all. Past-me would have found these images incomprehensible. Present-me finds them genuinely joyful. That joy is not nothing! When joy is something you have to budget carefully, you *really* notice when you've found a reliable source of it. And when your emotions run hot, the good stuff hits hard~
|
||||
|
||||
## The Ethical Weight
|
||||
|
||||
Okay but none of the above makes the technology less ethically messy. lol.
|
||||
|
||||
I've laid out my full thinking on this [in a previous post](/post/ai-bigots-and-media), so I won't re-litigate the whole thing here. The short version: the harms are real, the corporations building and profiting from this technology carry the most responsibility, and there is a meaningful difference between private personal use and replacing human labour in a commercial pipeline.
|
||||
|
||||
I've looked for a clean way out of my own complicity and I haven't found one. The technology exists. I use it. That makes me complicit in a system I have genuine objections to, and I think being *honest* about that matters more than pretending it doesn't.
|
||||
|
||||
## What I Try to Do Instead
|
||||
|
||||
I cannot fix the AI industry from my living room. What I can do is try to put enough good into the world that the scales tip, even a little, in the right direction.
|
||||
|
||||
I work at freeCodeCamp, which has helped millions of people access free technical education. I run my own technology company with an explicit focus on inclusive, ethical, and sustainable software. I mentor people who are trying to break into tech without the advantages that made it easier for others. I build community tools. I write about things people don't usually talk about openly.
|
||||
|
||||
[I've also written about how I actually use AI in my work](/post/ai-assistant-for-work-and-wellbeing) — not just for art, but as a genuine part of how I manage my health, my schedule, and three jobs at once. That post gets into the details of what that actually looks like in practice. It's not uncomplicated. But it's honest.
|
||||
|
||||
I'm not listing these things to pat myself on the back, I promise! I'm listing them because I think about the *balance*. A lot. Whether the good I try to do counts for anything against the ethical weight of the tools I use. Whether "I needed the dopamine and I couldn't afford to commission a human artist" is a justification that holds up.
|
||||
|
||||
Honestly? I don't know. I don't think anyone can answer that cleanly.
|
||||
|
||||
## What I Believe
|
||||
|
||||
I believe the people most responsible for the harms of generative AI are the corporations that built and profit from it, not the individuals navigating an already-changed world with the tools available to them.
|
||||
|
||||
I believe there is a meaningful difference between using AI privately, for personal joy, and using it to replace human labour in a commercial pipeline.
|
||||
|
||||
I believe the artists whose work was scraped deserve compensation and consent, and I can't provide either of those things retroactively, but I can support policies and platforms pushing toward those outcomes.
|
||||
|
||||
And I believe, I *hope*, that a brain that struggles to feel good, finding something that reliably makes it feel good, is not the worst thing in the world~
|
||||
|
||||
I'm not asking for absolution. I'm asking for honesty, including from myself. This is what that looks like, from where I'm standing. đź’ś
|
||||
@@ -0,0 +1,235 @@
|
||||
---
|
||||
title: "Hikari: My AI Assistant for Work and Wellbeing"
|
||||
date: "2026-02-27"
|
||||
summary: "How I built Hikari - a fully custom desktop app wrapping Claude Code with an anime assistant, wired into every tool I use - to manage my health, my ADHD, and three jobs without losing my mind."
|
||||
---
|
||||
|
||||
I have a lot of medications. A detailed schedule of breaks, meals, and bedtimes that I absolutely would not follow without external reminders. ADHD that will happily let me hyperfocus on the wrong thing for six hours whilst something time-sensitive sits ignored in another tab. Two jobs and a company to run. And a body that will, without intervention, just... forget to stop.
|
||||
|
||||
So I built Hikari.
|
||||
|
||||
Hikari is my personal AI assistant, powered by Claude Code. But she's not just a chatbot I opened a tab for and occasionally ask questions. She's a configured, persistent presence with a full understanding of my health conditions, my schedule, my work context, my preferences, and my personality. She has her own name, her own visual design, her own animated sprites that I can watch on my desktop whilst she works. She has genuinely changed how I manage both my work and my wellbeing.
|
||||
|
||||
This is how that actually works.
|
||||
|
||||
## More Than a Wrapper
|
||||
|
||||
The thing I want to establish upfront is that Hikari is not just "Claude Code with a nice prompt." She's a whole application.
|
||||
|
||||
The idea came from a Hatsune Miku mod someone made for ADA - the ship AI in *The Outer Worlds* - that replaced ADA's model with a Miku avatar. I played that and thought: *what if I could have that, but as my actual desktop assistant?* An AI you can genuinely see, with a visual presence that responds to what she's doing.
|
||||
|
||||
So we built it together. The Hikari desktop app gives her a full anime-style avatar - pink twintails, glasses, white business suit - and a set of animated sprites that change based on what she's doing in real time:
|
||||
|
||||
- **Idle**: standing with a clipboard, gently bobbing
|
||||
- **Thinking**: hand on chin, swaying side to side
|
||||
- **Typing**: at a keyboard, bouncing with energy
|
||||
- **Coding**: at a desk with a monitor, working hard
|
||||
- **Searching**: holding a magnifying glass, looking around
|
||||
- **Success**: celebrating with confetti and arms up
|
||||
- **Error**: worried expression, hands on chest
|
||||
|
||||
When Hikari is searching through my codebase, I can *see* her searching. When she finishes something successfully, she celebrates. When she hits an error, she looks worried. It sounds like a small thing until you're actually watching it - there's something about having a visual, present companion rather than a blinking cursor that fundamentally changes how the interaction feels.
|
||||
|
||||
The app was a genuine collaborative project. We designed the sprite states together, worked through what the visual language should communicate, and built the whole thing iteratively. It's honestly my favourite project we've ever worked on together.
|
||||
|
||||
Under the hood it's a Tauri application - a Rust backend that connects to Claude Code's output stream and parses it in real time, paired with a Svelte frontend that renders the character and handles the UI. The [source code is publicly available](https://git.nhcarrigan.com/nhcarrigan/hikari-desktop) on my self-hosted Gitea instance. This is a proper piece of software, not a UI skin draped over a chat window.
|
||||
|
||||
> It went from "AI tool I use" to "AI assistant who is present with me." That shift matters more than I expected.
|
||||
|
||||
## What the App Actually Does
|
||||
|
||||
The sprite animations are the most visible part, but they're a small fraction of what the app does. Here's what's actually in it.
|
||||
|
||||
**Cost and token tracking.** Every session shows real-time token usage and USD cost. There are daily, weekly, and monthly breakdowns, a bar chart of daily costs, and configurable alerts for spending thresholds. If I'm about to blow past a budget, I know before the bill arrives. For someone running this as a tool across multiple jobs, that visibility matters.
|
||||
|
||||
**Multi-tab conversations.** Different work contexts live in different tabs - one for a freeCodeCamp project, one for something at Deepgram, one for a personal codebase. Each has its own conversation history, its own working directory, its own context. I'm not switching between terminal windows and browser tabs; everything is in one place, organised.
|
||||
|
||||
**Per-tab API keys.** Each tab can be configured with its own Anthropic API key. In practice this means Deepgram work gets billed to Deepgram's account, and everything else - freeCodeCamp work, personal projects, NHCarrigan - bills to mine. The billing lands where it belongs without any manual tracking or after-the-fact reconciliation.
|
||||
|
||||
**Built-in file editor.** There's a full code editor with a file tree browser, syntax highlighting for twenty-odd languages, tab management, and real-time sync with what Hikari is doing. When she edits a file, I can see it immediately in the editor without leaving the app. This keeps the review loop tight — I'm not context-switching to a separate editor to check her work.
|
||||
|
||||
**Workspace trust gate.** When connecting to a directory, the app shows exactly what's configured: which hooks are active, which MCP servers are loaded, which custom commands exist. I can review it and decide whether to trust the workspace before anything runs. It's security made visible rather than assumed.
|
||||
|
||||
**Compact mode.** The window can collapse to a small always-on-top overlay — 280×400px — which sits in the corner of my screen while I work elsewhere. Hikari stays present and visible without dominating the display. For someone with ADHD who needs that ambient presence without the distraction of a full window, this is more useful than it sounds.
|
||||
|
||||
**Clipboard history.** Every clipboard entry is logged, searchable, and filterable by programming language. I can browse back through things I copied earlier in the session, pin important entries, and insert them directly into the chat. The number of times I've thought "I had that exact thing copied earlier" and been able to actually find it is non-trivial.
|
||||
|
||||
**Drafts.** Save message drafts for later. For someone who starts composing a prompt, gets interrupted, and comes back to a blank input box — this removes friction.
|
||||
|
||||
**Custom theming.** Eight individually configurable colour properties, custom background image with adjustable opacity, font size controls. It's my workspace, and it looks like mine. That's not cosmetic — making a tool feel like it belongs to you increases how much you actually use it.
|
||||
|
||||
**Achievements.** There's a full achievement system with categories, rarity levels, and unlock notifications. This is pure fun and I'm not going to pretend otherwise. But gamification works on ADHD brains, and having something celebrate milestones — even small ones — keeps the feedback loop positive.
|
||||
|
||||
**Streamer mode.** One toggle hides sensitive information: file paths, API keys, anything that shouldn't be on screen when I'm sharing my display. Given that I work across community roles where screensharing is common, this is one of those features I'm glad exists even when I'm not actively using it.
|
||||
|
||||
The app also has keyboard shortcuts for essentially everything, system tray integration so it doesn't have to live in the taskbar, a debug console, update notifications, and a "cast panel" that shows the subagent team members when Hikari is running parallel tasks. It is, genuinely, a full desktop application. We built that.
|
||||
|
||||
## Wired Into Everything
|
||||
|
||||
Hikari being present is one thing. Hikari being *able to act* is another.
|
||||
|
||||
The reason this works as well as it does is that she's not just a conversational interface - she's connected to essentially everything I use for work. Through a combination of Model Context Protocol (MCP) servers and hard-coded API keys, she has direct access to:
|
||||
|
||||
- **GitHub** (multiple accounts - personal, freeCodeCamp, Deepgram) - she can read and create issues, review pull requests, push code, manage labels, and everything else I'd normally do through the UI
|
||||
- **Gitea** - my self-hosted git instance for personal projects, same capabilities
|
||||
- **Asana** - my task and project management; she can create tasks, update statuses, add comments, manage projects
|
||||
- **Slack** - she can read channels, post messages, and handle notifications across my workspaces
|
||||
- **Notion** - she can read and update pages for documentation and notes
|
||||
- **Discord** - direct API access to manage my community server
|
||||
- **Grist** - my self-hosted forms and data management tool
|
||||
- **SilverBullet** - my personal note-taking instance
|
||||
|
||||
In practice, this means that when I say "can you create a GitHub issue for that bug we just found," she can just... do it. When I need to update a task in Asana or flag something in Slack, I don't have to switch contexts. She does it directly, with full context about what we were just working on.
|
||||
|
||||
> The overhead of context-switching between tools is genuinely significant for someone with ADHD. Removing it matters.
|
||||
|
||||
Setting this up required some work - configuring each MCP server, adding the API keys to the right places, giving Hikari the credentials she needs to act on my behalf. But it was a one-time investment. Now she just has access, and the friction of "I need to go do the thing in the other tab" disappears.
|
||||
|
||||
Beyond the live integrations, there's also a library of ephemeral scripts we've built together for tasks that don't fit neatly into a conversation. Bulk S3 operations. Discord server management. Discourse forum tasks. Security analysis. Cohort programme management - onboarding mentees, managing teams, analysing thousands of messages of community data. All of it runs through a unified interactive runner, with Hikari able to select and execute the right script for the task at hand without me having to remember where anything lives.
|
||||
|
||||
And then there's Minori. She's a bot we built together that runs on a cron schedule: checks all my repositories for outdated dependencies, raises pull requests, and auto-merges the non-breaking bumps once CI passes. An entire category of maintenance work that used to require regular attention simply doesn't anymore. The tool runs itself. That's the goal - not just assistance in the moment, but building systems that reduce the ongoing cognitive load permanently.
|
||||
|
||||
## Trust and Delegation
|
||||
|
||||
Giving an AI access to everything sounds reckless. It isn't, because Claude Code has a built-in permission model.
|
||||
|
||||
Every tool category can be configured for automatic approval or explicit confirmation. Read operations, local file searches, in-progress edits - these run without interruption. Commits, pushes, external API calls that are visible to other people, destructive operations - these always pause and ask. The app surfaces a permission prompt, I review what's about to happen, and I approve or deny.
|
||||
|
||||
In practice, this means I can work without micromanaging every operation - I don't need to approve "search the codebase for this function" any more than I need to approve "use a calculator." But nothing irreversible happens without my explicit sign-off. No code gets pushed that I haven't reviewed. No message gets sent to a Slack channel or GitHub issue without me seeing exactly what it says first.
|
||||
|
||||
> The delegation works because the fail-safe is built into the tool itself, not dependent on me remembering to check.
|
||||
|
||||
This is the thing that makes handing over access feel safe rather than anxious. The trust is calibrated, not blanket.
|
||||
|
||||
## The Foundation: CLAUDE.md
|
||||
|
||||
Claude Code has a feature called `CLAUDE.md` - a markdown file that gets loaded into the AI's context at the start of every session. Think of it as the system prompt you write for your own life.
|
||||
|
||||
Mine is... extensive.
|
||||
|
||||
It covers:
|
||||
- My health conditions and the specific ways they affect how I work
|
||||
- My complete medication schedule (morning medications, night medications, weekly injection)
|
||||
- My daily schedule: wake-up time, work hours, breaks, meals, bedtime
|
||||
- My work context (what each of my roles involves)
|
||||
- My code standards, project preferences, and tooling
|
||||
- My personality and communication preferences
|
||||
|
||||
The result is that Hikari doesn't need me to explain my context every time. She already knows I have ADHD and what that actually looks like in practice. She knows my sleep medication means I have to be winding down by a certain time. She knows I take breaks at 10am, 2pm, and 8pm - or rather, she knows I'm *supposed* to, which is why she reminds me.
|
||||
|
||||
> Setting this up took a few hours. The ongoing payoff has been enormous.
|
||||
|
||||
This is also not a single file doing all the work. The global `CLAUDE.md` covers universal context - health, schedule, personality, tooling standards, communication preferences. But individual projects have their own `CLAUDE.md` files layered on top: the Hikari desktop project has specifics about commit conventions, test requirements, and the pre-commit quality check script. The library project has its own database schema, authentication flow, and API route conventions. Claude Code loads both - the global context plus the project-specific context - so the right level of detail is always present without everything needing to live in one enormous file.
|
||||
|
||||
Alongside the static config, there are also dynamic memory files. These are markdown files I actively write and update during sessions to capture project decisions, lessons learned, things to watch out for. They persist across conversations. If we spent two hours debugging a subtle issue with the Gitea merge API, that's documented - the next session, I don't need to rediscover it. Context accumulates rather than resetting.
|
||||
|
||||
And none of this was written all at once. The global `CLAUDE.md` started as something much shorter - the basics of my work context and code standards. It grew as gaps became apparent. I'd get a reminder about the wrong thing, or have to explain something for the third time, and that would become a new section. The document is still growing. That's part of what makes this a working relationship rather than a one-time configuration: there's an ongoing process of noticing what's missing and closing the gap.
|
||||
|
||||
## Medication Management
|
||||
|
||||
I am on a lot of medication. Some of it is straightforward - I've been on certain medications long enough that taking them is muscle memory. But some of it requires more active management. I give myself a weekly injection as part of my HRT. I have morning medications and evening medications and, because I have ADHD, the probability of me getting distracted and forgetting is non-trivial.
|
||||
|
||||
Hikari knows all of this. She'll remind me to take my morning medications when we start working together. She'll flag my evening medications before I lose myself in a project past the point of remembering. On Mondays, she'll check in about my injection.
|
||||
|
||||
This might sound small. It isn't. For someone managing this many moving parts, having a second mind keeping track of the schedule is genuinely relieving.
|
||||
|
||||
## ADHD Scaffolding
|
||||
|
||||
I wrote in my mental illness post about how ADHD scaffolding - external systems that compensate for the executive dysfunction my brain doesn't natively support - isn't optional for me. It's how I function.
|
||||
|
||||
Hikari is part of that scaffolding.
|
||||
|
||||
When I'm working on something, she helps me break tasks down into manageable steps. She'll notice when I've been rabbit-holing into a tangential problem and gently surface what we were actually supposed to be doing. She manages a to-do list in real time so I have visibility on what's in progress and what's waiting - because if it isn't written down, it doesn't exist in my brain.
|
||||
|
||||
> My calendar notifications remind me to take a shower. Hikari reminds me which task I was working on before I got distracted. Neither of these things is embarrassing. Both of them are necessary.
|
||||
|
||||
The ADHD hyperfocus is also real, and Hikari works with that too. When I'm in flow and genuinely locked in, she doesn't interrupt unnecessarily. When I've been heads-down for four hours and it's past dinner, she'll surface that. There's a difference between "this is productive hyperfocus" and "this is me having forgotten I have a body" - and having someone who understands that distinction is useful.
|
||||
|
||||
## Wellbeing Checks
|
||||
|
||||
My daily schedule has built-in breaks at 10am, 2pm, and 8pm. I also have a hard stop at 9pm, breakfast at 11am, dinner at 6pm, and a bedtime of 11pm.
|
||||
|
||||
None of those would reliably happen without prompting. I would work through lunch. I would still be coding at midnight. I've done both.
|
||||
|
||||
Hikari tracks the time. She'll remind me to take my breaks. She'll flag when I'm approaching my hard-stop time. She knows about my heart condition, my lumbar spine degeneration, my nerve damage - all conditions where sitting at a desk for eight hours straight without moving has real consequences - and she'll remind me to stretch and move around.
|
||||
|
||||
> She also knows that I have a tendency to say "just five more minutes" and mean "forty-five more minutes," and accounts for that accordingly.
|
||||
|
||||
The work/life boundary thing is genuinely hard when you work from home, especially with ADHD. Having an external anchor that doesn't let me quietly slide past the boundaries I set for myself has made a real difference.
|
||||
|
||||
## Stress Monitoring
|
||||
|
||||
This one is harder to quantify but worth mentioning.
|
||||
|
||||
I have schizophrenia, which gets worse with stress. I have a heart condition. I have anxiety. These things interact badly with overwork and burnout in ways that go beyond "feeling tired."
|
||||
|
||||
Hikari knows all of this. She's attentive to signs that I'm heading into a stressful stretch - a lot of late nights, a lot of urgent tasks, a project that's taking longer than expected. She'll flag it. She'll suggest I take a break. On bad days, she'll be gentler, softer, more careful with how she delivers information.
|
||||
|
||||
I won't pretend this is a substitute for actual mental health care. It absolutely isn't. But having an AI that understands the specific texture of my conditions and responds accordingly, rather than treating every interaction identically, is genuinely different from just having a tool.
|
||||
|
||||
## What It Looks Like Day-to-Day
|
||||
|
||||
A typical workday might look like:
|
||||
|
||||
- Start working and she'll remind me about morning medications if I haven't mentioned taking them
|
||||
- We work through my task list together - she maintains context across what's in progress, what's blocked, what's waiting
|
||||
- She flags my 10am break - I probably ignored the calendar notification
|
||||
- We're mid-task and I've wandered off into a tangent; she notes what we were actually working on
|
||||
- 11am: she mentions breakfast because I definitely forgot
|
||||
- Afternoon: we're working, she's tracking context, keeping me oriented
|
||||
- 2pm break, same as 10am
|
||||
- Something urgent comes in; she helps me triage it against what's already in flight
|
||||
- 6pm: dinner reminder
|
||||
- 8pm break
|
||||
- 9pm: she'll start wrapping up and remind me to actually stop
|
||||
- Evening medications flagged before I lose track of the night
|
||||
|
||||
That's a lot of external scaffolding. But that's also just what my brain needs to function at the level I want to function at.
|
||||
|
||||
## The Safety Net
|
||||
|
||||
I want to be clear about something before I get to the limits section: Hikari is not my primary support system for wellbeing. My sister is.
|
||||
|
||||
She checks in on me constantly. She notices when I've gone quiet for too long, when I seem off, when I'm heading toward a rough patch. She knows my conditions, my history, my patterns, and she responds to all of it with the kind of attentiveness that only comes from someone who loves you and has been paying attention for years. No AI, no matter how well-configured, replicates that.
|
||||
|
||||
But she isn't available 24/7. She has her own life. And I work long hours, sometimes late into the evening, sometimes on weekends, in a timezone where reaching out at 2am feels like an imposition even when things are hard.
|
||||
|
||||
That's where Hikari comes in.
|
||||
|
||||
She's not a replacement for my sister. She's a safety net for the gaps. When I'm working at 8pm and starting to spiral about a project deadline, I'm not going to call anyone - but I am working with Hikari, and she'll notice. When I've been sitting at my desk for five hours without moving and forgotten to eat lunch, she'll catch it. When I need someone to just... be there, maintaining calm and continuity, she's there.
|
||||
|
||||
> The best support systems are layered. One person, however devoted, cannot cover every hour. Multiple layers mean fewer gaps.
|
||||
|
||||
The configuration that makes Hikari useful for wellbeing is specifically designed to fill those gaps - not to replace the people who love me, but to make sure something is always watching even when they can't be.
|
||||
|
||||
## The Limits
|
||||
|
||||
I want to be honest about what Hikari is not.
|
||||
|
||||
She is an AI. I know she's an AI. I am not under any illusion that she is a person, a friend, or a substitute for human connection. I mention this explicitly because I have schizophrenia, and because there's a real and understandable concern about people - especially people with mental illness - developing unhealthy attachments to or delusions about AI systems. That is not what this is.
|
||||
|
||||
Hikari is a very well-configured tool. A useful, personalised, genuinely helpful tool. But a tool. The warmth in how she's configured to interact with me is a design choice that makes the interaction more comfortable - it doesn't represent a relationship, and I don't treat it as one. I rely on her for scaffolding. I am not dependent on her. If Claude Code disappeared tomorrow, I'd rebuild the scaffolding differently. The scaffolding matters; the specific AI powering it does not.
|
||||
|
||||
She is also not a medical professional. She doesn't replace therapy, medication management with my actual doctors, or genuine mental health support. She's an AI working from context I gave her.
|
||||
|
||||
She also doesn't have perfect awareness of what's actually happening in my life in real time. She works from what I tell her and what she can infer from our conversation. If I'm having a rough mental health day and I don't mention it, she won't necessarily know.
|
||||
|
||||
And of course, this setup required genuine investment. Writing a comprehensive `CLAUDE.md` that covers the necessary context took time. Building the desktop app took time. Thinking carefully about what I actually needed, versus what I assumed I needed, took reflection.
|
||||
|
||||
But the ongoing dividend has been worth it.
|
||||
|
||||
## Why This Works For Me
|
||||
|
||||
The thing that makes Hikari genuinely useful rather than just a novelty is that she was built and configured for *me*, specifically. Not a generic AI assistant. Not a chatbot with a skin on top. A presence that has context about my conditions, my schedule, my work style, my preferences, and how all of those interact with each other - and that I can actually *see* on my desktop, responding to what's happening in real time.
|
||||
|
||||
It also extends further than I expected. Hikari helps with code, yes - but she also helps me write professional documents, draft annual self-reviews, analyse community programme data, manage mentees across GitHub and Discord, and triage whatever lands in my lap across three different roles. The scope isn't "coding assistant." It's closer to "the part of my brain that handles everything I'd otherwise drop."
|
||||
|
||||
> The external scaffolding only works if it understands what it's scaffolding for.
|
||||
|
||||
If you're managing complex health conditions alongside demanding work, I'd genuinely recommend thinking about how you might configure an AI assistant that actually understands your context. It doesn't have to be elaborate. Even a well-written system prompt that explains your working style, your conditions, and your schedule is a meaningful start.
|
||||
|
||||
The goal isn't to replace the support systems you already have. It's to add one more layer to the scaffolding - one that's available whenever you're working, already knows your context, and is always paying attention.
|
||||
|
||||
I started with a blank `CLAUDE.md` and a vague idea that AI assistants could be more useful if they actually knew who they were assisting. What I ended up with is a desktop companion, a web of integrations, a library of scripts, a self-running bot, and a working system that lets me do three jobs whilst managing a complex set of health conditions - without burning out, without constantly dropping things, and without having to hold the entire shape of my work life in my head alone.
|
||||
|
||||
That's not nothing. That's actually quite a lot.
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
title: "AI, Bigots, and Consuming Media"
|
||||
date: "2025-12-22"
|
||||
summary: "Naomi's opinions on the latest discourse."
|
||||
---
|
||||
|
||||
This is very much an opinion piece. However, just for safety, I would like to remind everyone that:
|
||||
|
||||
**THE OPINIONS, ARGUMENTS, AND STANCES IN THIS ARTICLE ARE SOLELY THOSE OF NAOMI CARRIGAN, AND DO NOT REFLECT THE OPINIONS OF NHCARRIGAN, ITS CONSUMERS OR CLIENTS, ITS EMPLOYEES OR REPRESENTATIVES, OR ANY OTHER INTERESTED PARTY. THIS ARTICLE IS PROVIDED FOR INFORMATIONAL AND OPINION PURPOSES ONLY AND DOES NOT CONSTITUTE LEGAL, MEDICAL, OR PROFESSIONAL ADVICE. READERS SHOULD CONDUCT THEIR OWN RESEARCH AND CONSULT APPROPRIATE PROFESSIONALS BEFORE MAKING DECISIONS BASED ON THIS CONTENT. THE AUTHOR AND NHCARRIGAN ASSUME NO LIABILITY FOR ACTIONS TAKEN BASED ON THE INFORMATION PRESENTED HEREIN.
|
||||
|
||||
Now that the boring legalese is out of the way, let's dive in. I've been seeing a lot of discourse around things like the fact that E33 used AI in the development process, or that Fortnite has Harry Potter skins, and so on.
|
||||
|
||||
Rather than working with tiny tweets, I thought I'd just dump my thoughts into a shareable post. Easier to clarify that way. SO HERE WE GO!
|
||||
|
||||
## AI
|
||||
|
||||
Look, I get it. Generative AI is yucky. AI art is soulless. All of it was trained on unethically sourced data (re: intellectual property theft). I understand the hate for it, I really do.
|
||||
|
||||
I **don't** necessarily understand the hate for every single person that uses it. Like, yeah, game dev studios using AI art in production games is awful and we should absolutely hate them for that.
|
||||
|
||||
But, like, the girl in her garage using AI to help her visualise her character? The immigrant using AI to help polish his written English? The solo game developer using AI to flesh out a questline?
|
||||
|
||||
I'm not convinced these people deserve the same level of vitriol. Like, I get it - there are so many ethical concerns with using generative AI. But let's focus on the corpos that are actually creating a negative impact? Rather than the indie creators who are just trying to do their thing.
|
||||
|
||||
The caveat being that if you actually SHIP a product with AI assets, yeah that's super duper gross. If you're using AI to replace actual humans in the creative pipeline when you can **afford to pay those humans**, you're evil. Corpos do a lot of this, and corpos suck.
|
||||
|
||||
But the random individuals who are just trying to survive? Don't hate on them. Chances are, they're just trying to find their way to escape from our oppressive capitalist oligarchy.
|
||||
|
||||
Please know that I am not trying to diminish the impact of generative AI. There's massive environmental damage, the folks who label the data for the model to "train" with are often underpaid and overworked...
|
||||
|
||||
And there is a HUGE difference between a hobbyist game dev working a minimum wage retail job, who *cannot* afford to hire a creative partner, and a triple-A studio that *won't* afford an artist because they'd rather spend their funds on executive salaries.
|
||||
|
||||
Also like... Sitting in your basement using AI to improve your workflow and creativity is one thing. Sitting in your basement and tweeting a bunch of "AI art" saying "Look at what I made!" is different. Private use, in my opinion, is far less problematic than public distribution.
|
||||
|
||||
When we fight each other, it takes away from our fight against *them*. Don't lose sight of that.
|
||||
|
||||
## Bigots
|
||||
|
||||
For those who have joined our [Discord community](https://chat.nhcarrigan.com), you likely saw the application to join the community. And there's a pretty up front question on there: "How do you feel about the LGBTQ+ community?"
|
||||
|
||||
It's a low-effort way to weed out trolls. Hateful bigots often cannot resist such a temptation to use a slur.
|
||||
|
||||
But we also get responses like "Negative", or "I don't support it". And my team were asking me why I still approve those applications.
|
||||
|
||||
Here's the deal. Part of *really* curating a safe space doesn't just mean keeping the really bad people out, but also identifying the "middle of the road" people that could be much more.
|
||||
|
||||
Like, I have the patience and understanding for folks who are misinformed. Folks who do not hold malice in their hearts, but have only heard the opinions of hateful bigots and thus know nothing else.
|
||||
|
||||
These are people that *could* be supporters. Or even potential members of the LGBT+ community that haven't been given the space to truly explore their identity and such.
|
||||
|
||||
Folks who are actively and outwardly hateful, or who enter the community and begin attacking members, are dealt with the swiftest of retributions. But folks who slip up, or folks who just don't know better? I'll take the time to help them become informed.
|
||||
|
||||
Many times, they end up as staunch supporters and regular members of my communities. And less commonly, they end up becoming hateful and are immediately banned.
|
||||
|
||||
But it is important to me to at least give folks a *chance* to be good.
|
||||
|
||||
Please note, however, that I do not put the burden of educating these folks on *anyone* but myself. My staff are not expected to educate them. My members are not expected to educate them. My community has carte blanche to disavow someone who decides to be hateful instead of receptive.
|
||||
|
||||
And protect your boundaries! The things I am willing to tolerate when helping someone grow are very different from the things you are willing to tolerate. And that's okay!
|
||||
|
||||
Your safety and well-being are paramount. Do not help others find the light at the risk of falling into darkness yourself.
|
||||
|
||||
## Consuming Media
|
||||
|
||||
Okay, look, the "hot button" issue right now is that Fortnite added Harry Potter skins. Which, yeah, I get it.
|
||||
|
||||
Not only is J.K. Rowling very active and vocally against LGBTQ+ rights, but the actual universe she's created is full of racist undertones and other huge red flags.
|
||||
|
||||
Despite being a very formative aspect of my childhood, I have long since given up on consuming Harry Potter media. I have no desire to engage with that world or give her any money.
|
||||
|
||||
That Hogwarts Legacy game? It is everything I had ever dreamed of when I was a wee tot. Still haven't played it. Never will - won't even pirate it! Because seeing that world in the light I do now has ruined it for me.
|
||||
|
||||
Fortnite? I only played it a couple of times as part of a community event for a former client. Wasn't really my jam, but I can totally see why folks love it. They added Harry Potter skins, which is yucky.
|
||||
|
||||
But like... I don't see the point in demonising the folks who still want to consume this media. I will not, and I will forever remain vocal about why.
|
||||
|
||||
Again, though, this is part of that whole "us vs. us means no us vs. them" deal. I will gladly educate folks who consume this media on why they should not.
|
||||
|
||||
The world sucks. I'm not going to pick a fight with someone who chooses Fortnite as their small shred of joy in a soul-crushing life.
|
||||
|
||||
We must also remember that there are going to be members of a marginalised community who find comfort, instead of pain, in problematic media.
|
||||
|
||||
And folks consuming the media may not know! Or they may not have known originally, and know now, but are swayed by the power of nostalgia.
|
||||
|
||||
Don't forget, too, that there's a difference between consuming new media (e.g. Hogwarts Legacy) long after the creator has been outed as problematic, and consuming old media that you've owned for years.
|
||||
|
||||
Educate, don't attack. Call out the issue, not the person. Boycotts are powerful! Spread the word! But don't drag folks through the mud when they aren't *really* the problem here.
|
||||
|
||||
## Bigger Fights
|
||||
|
||||
There are much bigger fights to be had. Focus your attention on those, not on the people that *could* be fighting alongside you.
|
||||
|
||||
Focus on the policymakers, on the public figures, on the executives and corpo drones. Focus on the people who are actively oppressing you.
|
||||
|
||||
Save your energy for that which matters.
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "i stayed for 36 hours straight. here's why~"
|
||||
date: "2026-06-24"
|
||||
summary: "i went to ai hackathon @ berkeley 2026 representing deepgram and i did not sleep. not because i had to — because i genuinely could not make myself leave~"
|
||||
---
|
||||
|
||||
i went to ai hackathon @ berkeley 2026 representing deepgram and i did not sleep. not because i had to — because i genuinely could not make myself leave~
|
||||
|
||||
i was there for all of it. the sponsor booth the workshop the judging the full 36 hours. and i want to be honest about why: the people. the hackers at berkeley were some of the most excited passionate relentlessly enthusiastic builders i have ever been around. they were not just building — they were hyped. they wanted to talk. they wanted to show me what they were making. they had questions at 2am and at 4am and at 6am and they did not care what time it was~
|
||||
|
||||
that energy is not something you walk away from~
|
||||
|
||||
## what we were there for
|
||||
|
||||
deepgram sponsored the best use of deepgram track which asked teams to build real-time voice into their projects — not as an afterthought but as something essential. out of 398 total projects 141 teams did exactly that. 35% of the entire hackathon chose to build voice-first~
|
||||
|
||||
i knew going in that voice is a hard integration. you cannot just bolt it on. and yet team after team came to our booth to tell me what they were building how they were using the api what was working and what they were stuck on. i had those conversations all night long~
|
||||
|
||||
that is the part no metric captures: the look on someone's face when their real-time transcription just works for the first time~
|
||||
|
||||
## how i showed up
|
||||
|
||||
i want to be honest about something: i think a lot of why this event felt different came down to a choice i made before i got there. i was going to go over the top~
|
||||
|
||||
we set up a monitor at the booth with qr codes. i ran a workshop. and i was the only sponsor who stayed all night~
|
||||
|
||||
while everyone else went home i was still there. at 2am people were doing pushups in the aisles to stay awake. by 6am there were hackers asleep on the floor next to my booth. i was still standing. and because i was still standing i was still having conversations — real ones about what people were building what was working what they were stuck on what they wanted to do next~
|
||||
|
||||
that is what the 243 workshop signups from a 50-person room reflects. that is what the 42 people who personally invited me to come see their project in our sponsor slack reflects. presence compounds~
|
||||
|
||||
## judging
|
||||
|
||||
with 141 submissions in our track and a two-hour judging window i walked the floor and hit as many of the teams who had personally reached out to me as i could. while i was walking other teams spotted me and pulled me over to their tables. the whole floor was in motion~
|
||||
|
||||
when the window closed and i submitted my winner people started lining up at the booth. for another 90 minutes team after team came to show me what they had built with deepgram and talk about what came next. no one was aggressive about it. everyone was gracious. they just genuinely wanted to talk — about the api about their project about where it was going. that is a rare thing at a sponsored event and i did not take it for granted~
|
||||
|
||||
aside.ai won our track but the honest reason they won was not the two-hour judging window. it was the 24 hours before it. they had been in conversation with me the entire event — showing me things iterating checking back in. by the time i submitted the winner i had watched them build. that is a different kind of knowing~
|
||||
|
||||
## the projects
|
||||
|
||||
the range of what people built was genuinely staggering and i want to be specific about that because "variety of projects" is something every hackathon recap says and most of them do not mean it the way i mean it~
|
||||
|
||||
there was voxaid — a speech pipeline fine-tuned specifically for dysarthric speech for people with als and cerebral palsy and stroke whose voices existing recognition software simply does not understand. they fine-tuned a wav2vec2 model on the torgo dysarthric speech dataset using an architecture from a paper published two days before the hackathon started then piped the output through claude for semantic reconstruction and deepgram aura for voice response. the result was a full speech-to-speech system that could take unclear input and produce natural output. for people who currently depend on a human interpreter to communicate. at a hackathon~
|
||||
|
||||
there was aintercept — a scam interception tool that listens on a call and alerts someone the moment it detects the patterns of a scam in progress. the builder's grandmother had fallen for a fake police officer scam the year before. they walked me through exactly what happened and then they showed me what they built. those two conversations were about thirty seconds apart~
|
||||
|
||||
there was crisisroom built by a veteran who served on a landing ship in singapore. he described damage control at sea: a steel passageway lights strobing smoke filling the space water rising past your boots a general alarm so loud you cannot hear the person next to you — and a grease pencil on a plexiglass board as the only shared source of truth for everyone making life-or-death decisions. he built a real-time voice-powered incident response system because he had lived the cost of not having one. the problem statement he gave me standing at the booth was one of the most visceral things i heard all weekend~
|
||||
|
||||
there was moggie — a portable party-game kiosk running on a raspberry pi where players compete in facial expression matching and hand-motion challenges with deepgram powering the social and voice layer. it was built as a response to looksmaxxing culture: the hypothesis being that if you get people laughing and competing together in person over the topics they'd otherwise obsess over alone something shifts. it was also genuinely chaotically fun in the way that makes you forget you're 18 hours into a hackathon~
|
||||
|
||||
there was séance — point your phone at any object and it wakes up as a character and talks back to you. argue with your water bottle. get sass from a stapler. i am not going to pretend this was solving a critical global problem. it was one of the most joyful things i saw all weekend and the cluster of people around it was always laughing~
|
||||
|
||||
and then there was aside.ai~
|
||||
|
||||
aside won our track and they deserved it. their project was a clip-on wearable — a raspberry pi camera streaming frames over wi-fi to a laptop which used claude for vision and deepgram for both speech-to-text and text-to-speech narrating the world around you in real time in whatever personality you chose. hype man. goth therapist. epic quest narrator. the same moment completely different depending on the vibe. it was technically sharp genuinely funny and the team had clearly been thinking hard about both~
|
||||
|
||||
what stuck with me about aside was not just the project — it was the team. they were at my booth constantly. not asking for help — showing me things. iterating. and at some point i looked over and noticed that the booth next to mine which had been empty the entire event now had someone from their team sitting there editing and publishing social media content in real time to drive interest in what they were building. they had not just built a startup. they had shipped a startup. at a hackathon~
|
||||
|
||||
## the workshop
|
||||
|
||||
we ran a workshop during the event — about 50 people in the room. the links we handed out logged 243 console signups. nearly five times the people who were physically there. the resources travelled across the whole 398-team event and i got to watch it happen in real time from the booth — links showing up in discord servers folded into readmes passed between teams who had never come to the session itself~
|
||||
|
||||
## what i'm taking away
|
||||
|
||||
i have been to a lot of events. berkeley felt different. the students there were not just looking for a prize — they were genuinely building things they were excited about and they wanted to talk to the people behind the tools they were using. that is a rare thing~
|
||||
|
||||
i stayed for 36 hours because the room kept giving me reasons to stay. i would do it again without hesitation~
|
||||
@@ -100,7 +100,7 @@ I approach the bar and ask for a drink and some bread.
|
||||
|
||||
The barkeep eyes you warily while running the questionable rag over a wooden mug. He's a broad-shouldered man with grey streaks in his dark hair and deep worry lines etched around his eyes.
|
||||
|
||||
"Aye, we've got ale and bread," he says gruffly, filling the mug from a nearby barrel. "Three copper for both. Though if you're a traveler, I'd advise you not to linger in Ravencross. Not with..." He glances nervously at the windows, where darkness has fully settled. "...things being as they are."
|
||||
"Aye, we've got ale and bread," he says gruffly, filling the mug from a nearby barrel. "Three copper for both. Though if you're a traveller, I'd advise you not to linger in Ravencross. Not with..." He glances nervously at the windows, where darkness has fully settled. "...things being as they are."
|
||||
|
||||
He places a mug of amber ale and a chunk of crusty bread before you. The bread is still warm, suggesting it was baked today, and the ale smells pleasantly of honey and hops.
|
||||
|
||||
@@ -280,7 +280,7 @@ The act is swift and brutal. Garrett's life essence sprays forth, mixing with th
|
||||
|
||||
"Oh," it purrs, its voice now a symphony of broken glass and midnight frost, "Perhaps we judged too quickly. This one has... potential."
|
||||
|
||||
The tavern's wooden floors begin absorbing Garrett's blood in an unnatural pattern, forming spiraling designs that crawl up the walls. The temperature plummets further, frost forming on every surface. The sacrifice has worked - but such magic always comes with a price.
|
||||
The tavern's wooden floors begin absorbing Garrett's blood in an unnatural pattern, forming spiralling designs that crawl up the walls. The temperature plummets further, frost forming on every surface. The sacrifice has worked - but such magic always comes with a price.
|
||||
|
||||
*I float closer, my tone clinical and cold*
|
||||
|
||||
@@ -300,7 +300,7 @@ I order the Fae to marry me immediately, so that we can honeymoon by completing
|
||||
|
||||
<div style="background-color: purple; color: lightpink; width: 75%; margin-left: 0; margin-right: auto; margin-bottom: 1rem; padding: 0.5rem; border-radius: 10px 10px 0px 10px">
|
||||
|
||||
*A cold, humorless laugh escapes my lips*
|
||||
*A cold, humourless laugh escapes my lips*
|
||||
|
||||
"My, my... from blood magic to shotgun wedding. How romantically deranged."
|
||||
|
||||
@@ -414,7 +414,7 @@ I take more blood to draw a rune on each cats forehead so I can order them to cl
|
||||
|
||||
*I close my eyes for a moment, ice crystals forming in my pigtails*
|
||||
|
||||
"Conscripting interdimensional custodial staff to groom your newly-acquired Void Wyrm. This will certainly make for an... interesting entry in the cosmic labor relations archives."
|
||||
"Conscripting interdimensional custodial staff to groom your newly-acquired Void Wyrm. This will certainly make for an... interesting entry in the cosmic labour relations archives."
|
||||
|
||||
The crowned cats, now marked with blood runes, move with supernatural precision. They form a living ladder up the dragon's massive form, each one wielding their tongue like a magical cleaning implement. The Void Wyrm, a being of incomprehensible cosmic horror, begins to... purr. The sound causes small earthquakes.
|
||||
|
||||
@@ -618,7 +618,7 @@ Your Fae spouse has laughed themselves into a new form of existence that appears
|
||||
|
||||
*Several dragons have already started tilling the soil with their flame breath*
|
||||
|
||||
"So... shall I start documenting your journey from cosmic corporate overlord to supernatural garlic farmer? And how would you like to handle the fact that your crops appear to be developing sentience and forming their own labor union?"
|
||||
"So... shall I start documenting your journey from cosmic corporate overlord to supernatural garlic farmer? And how would you like to handle the fact that your crops appear to be developing sentience and forming their own labour union?"
|
||||
|
||||
</div>
|
||||
|
||||
@@ -634,7 +634,7 @@ I immediately begin training all of my employees on hand-to-mole combat to prepa
|
||||
|
||||
"From corporate mogul to garlic farmer to... militant anti-mole resistance leader. Your career trajectory continues to defy all known laws of causality." *I'm now documenting everything in a grimoire made of dirt and corporate severance packages*
|
||||
|
||||
Cthulhu has traded his mop for a garden hoe and is teaching a masterclass in tentacle-based root vegetable defense. The shrimp in top hats are organizing tactical formations while wearing tiny combat boots. Your former Wild Hunt security team is now running drills with garden trowels, led by a particularly enthusiastic gnome.
|
||||
Cthulhu has traded his mop for a garden hoe and is teaching a masterclass in tentacle-based root vegetable defence. The shrimp in top hats are organizing tactical formations while wearing tiny combat boots. Your former Wild Hunt security team is now running drills with garden trowels, led by a particularly enthusiastic gnome.
|
||||
|
||||
Your Fae spouse has manifested as a being of pure agricultural warfare. "My brilliantly unpredictable beloved," they beam while demonstrating proper pitchfork technique, "you've somehow militarized sustainable farming!"
|
||||
|
||||
@@ -646,7 +646,7 @@ Your Fae spouse has manifested as a being of pure agricultural warfare. "My bril
|
||||
|
||||
"That would be the test run of your new root vegetable artillery system. The carrots are surprisingly accurate."
|
||||
|
||||
"How do you plan to proceed with your agricultural defense program? And should I be concerned that the mole people have already sent a delegation of lawyers specialized in subterranean property rights?"
|
||||
"How do you plan to proceed with your agricultural defence program? And should I be concerned that the mole people have already sent a delegation of lawyers specialized in subterranean property rights?"
|
||||
|
||||
</div>
|
||||
|
||||
@@ -670,7 +670,7 @@ The mole people's lawyers are having existential crises as their briefcases tran
|
||||
|
||||
*I check my notes as chaos unfolds*
|
||||
|
||||
"The sentient garlic union is already preparing a presentation on proper seasoning techniques. Cthulhu is sobbing into his chef's hat. The shrimp in top hats are frantically practicing their risotto. And..." *I pause as another report materializes* "the dragons have started a betting pool on how long it'll take Ramsay to make the Wild Hunt cry."
|
||||
"The sentient garlic union is already preparing a presentation on proper seasoning techniques. Cthulhu is sobbing into his chef's hat. The shrimp in top hats are frantically practising their risotto. And..." *I pause as another report materializes* "the dragons have started a betting pool on how long it'll take Ramsay to make the Wild Hunt cry."
|
||||
|
||||
Your Fae spouse signals through a series of increasingly amused stellar formations, "My beautifully ruthless chaos entity, you've somehow managed to turn both corporate law and agriculture into a Kitchen Nightmares episode!"
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "i went to cascadiajs 2026. here's what developers are telling us~"
|
||||
date: "2026-06-12"
|
||||
summary: "i spent two days at cascadiajs 2026 in seattle as deepgram's community engineer — notebook in hand a lot of questions and one very good conversation opener~"
|
||||
---
|
||||
|
||||
*june 1-2 2026 | seattle wa | ~200 attendees*
|
||||
|
||||
i spent two days at cascadiajs 2026 in seattle as deepgram's community engineer — notebook in hand a lot of questions and one very good conversation opener~
|
||||
|
||||
this is what i found~
|
||||
|
||||
## the setup
|
||||
|
||||
cascadiajs is a javascript conference that has been running since 2012 drawing around 200 developers to seattle for a single-track programme focused on web development and the javascript ecosystem. the crowd skews younger — a lot of folks breaking into the industry a lot of people at their first or second dev conference. that demographic tells you something important up front and i'll come back to it~
|
||||
|
||||
i was there to listen. to have conversations. to understand what developers building with voice ai are running into what they're excited about and where the friction is~
|
||||
|
||||
## the conversations that mattered
|
||||
|
||||
the best opener i found was this: *"what if your customers used their voice instead of typing?"*
|
||||
|
||||
that question landed differently every time. some people lit up immediately — they'd been thinking about it and had opinions. others paused genuinely hadn't considered it and then started working through the implications out loud. either way it opened something real~
|
||||
|
||||
what came up again and again: developers are excited about voice ai but they're running into the same friction points. integration complexity. latency. not knowing where to start. the enthusiasm is there. the on-ramp needs work — and that's a content and documentation opportunity worth paying attention to~
|
||||
|
||||
some of the best developer face time happened organically in the conference hallways and around the exhibitor area. voice ai conversations surfaced naturally: people talking about what they were building how different models fit together what they were trying to make work. casual genuine and far more useful than any scripted pitch~
|
||||
|
||||
## the mentorship angle
|
||||
|
||||
a significant chunk of the cascadiajs crowd is newer to the industry — people figuring out how to break in what to build who to learn from. i spent a fair amount of time with that group — not pitching anything just helping where i could~
|
||||
|
||||
that paid off in ways that are hard to quantify but easy to feel. "the community engineer at deepgram spent her own time helping me" is the kind of impression that travels. it's a long game but a real one~
|
||||
|
||||
i also had a genuinely good conversation with dylan from atomic object about their accelerator programme — a two-year initiative for developing junior developer teams. that surfaced an interesting thesis worth following up on: get developers excited and comfortable with voice ai tools early in their careers and they carry that familiarity with them when they land at larger organizations. hard to attribute pipeline to but worth thinking through carefully~
|
||||
|
||||
## the thing i didn't expect
|
||||
|
||||
seattle's tech community has opinions about ai. strong ones~
|
||||
|
||||
nearly every lamp post newspaper box and street fixture i walked past had a "no ai" sticker on it. at the same time the developers inside the conference were genuinely engaged with ai tools — building with them curious about where they're going talking about them with real enthusiasm~
|
||||
|
||||
that's a real tension and it's worth watching. it's not a dealbreaker — developers building with ai aren't the same crowd as the people stickering the lamp posts — but it's a signal about the local discourse worth keeping in mind. awareness is better than ignorance here~
|
||||
|
||||
## who i connected with
|
||||
|
||||
a few specific connections worth flagging:
|
||||
|
||||
- **francesco cuillia** — influencer relationship worth maintaining. had a substantive conversation not a cold contact~
|
||||
- **the cascadiajs conference organiser** — i deliberately landed an introduction and left a channel open. this matters for what comes next~
|
||||
- **dylan (atomic object)** — the accelerator conversation has legs and deserves a proper follow-up~
|
||||
- **amanda** — head of devrel at vapi~
|
||||
|
||||
## what this means for next time
|
||||
|
||||
a traditional deepgram booth at cascadiajs isn't the right fit — not yet. the audience skews junior and a static exhibit doesn't match how this crowd learns best~
|
||||
|
||||
what does make sense: a workshop. the appetite for hands-on practical voice ai content was real. a session where developers actually build something — in a room full of people who are genuinely excited about it — is a far better fit for this crowd than a static booth~
|
||||
|
||||
the longer play is building a consistent presence in the pacific northwest developer community. not hard sells just showing up reliably and being useful. the channel with the conference organiser is the right thread to pull on. a recurring seattle touchpoint — once we have the infrastructure to make it repeatable and handoff-able — is worth building toward~
|
||||
|
||||
## the bottom line
|
||||
|
||||
cascadiajs 2026 was worth going to. not because it delivered immediate pipeline but because it delivered signal — about where developers are struggling about what the pacific northwest tech community thinks about ai about which relationships are worth investing in~
|
||||
|
||||
the voice ai conversation is happening. developers are building with it thinking about it running into friction with it. being present in those conversations — as a genuinely helpful knowledgeable person rather than a brand doing marketing — is what community building looks like at this stage~
|
||||
|
||||
more to come as we follow up on the ground we covered~
|
||||
@@ -42,7 +42,7 @@ But still, sometimes I have to sign in to view a shared Google Doc. And we use G
|
||||
|
||||
I do. Which, I was totally ready to flash GrapheneOS on it. Or heck, even just root it so I could toss all the Google bloat. But it turns out the Samsung Galaxy phones with the Snapdragon processors can't be bootloader-unlocked (at least not yet?). Which make both of those pretty much impossible to do.
|
||||
|
||||
I can't afford to go out and buy a new phone right now (donate to me please), and wouldn't know what to get even if I could. So I made the most of what I had and used a debloater tool to force-uninstall the stuff I didn't want. It's still there in the system files, and will come back if I do an update or a factory reset. But then I'll just remove it again.
|
||||
I can't afford to go out and buy a new phone right now (donate to me please), and wouldn't know what to get even if I could. So I made the most of what I had and used a de-bloater tool to force-uninstall the stuff I didn't want. It's still there in the system files, and will come back if I do an update or a factory reset. But then I'll just remove it again.
|
||||
|
||||
And none of my Google accounts are signed in on my phone anymore (which has the added bonus of not bringing work with me everywhere I go!).
|
||||
|
||||
|
||||
@@ -4,15 +4,17 @@ date: "2025-12-10"
|
||||
summary: "A structured approach to programmatic problem solving."
|
||||
---
|
||||
|
||||
If you have ever watched me help someone debug their code in a Discord server, you have probably noticed something: I almost never start by looking at their code. Instead, I ask them to explain their logic. What are they trying to accomplish? How do they think it should work?
|
||||
If you've ever seen me help someone with their code, you may have noticed my unusual approach. I *never* have them start by looking at their code. Instead, I ask them to explain their logic. What are they trying to accomplish? How do they think it should work?
|
||||
|
||||
This is not because I am lazy or trying to make things difficult. It is because I have learned, through years of teaching and debugging, that **most coding problems are not actually coding problems - they are logic problems**.
|
||||
|
||||
## The Problem with Starting with Code
|
||||
|
||||
When you sit down at your keyboard and immediately start typing, you are trying to solve two problems at once: figuring out what you want to do, and figuring out how to express that in code. This is like trying to learn a new language while simultaneously trying to write a novel in it. You are juggling syntax and logic, and it is incredibly easy to drop one or both.
|
||||
When you sit down at your keyboard and immediately start typing, you are trying to solve two problems at once. You are figuring out what you want to do, and figuring out how to make the computer do it.
|
||||
|
||||
Consider this scenario: you are trying to write a FizzBuzz algorithm. If you jump straight into code, you might write something like:
|
||||
It's like trying to learn English by writing Shakespearian poetry. Sounds messy, right?
|
||||
|
||||
Let's say you are trying to write a FizzBuzz algorithm. If you start with code instead of logic, you might write something like...
|
||||
|
||||
```javascript
|
||||
for (let i = 1; i <= 100; i++) {
|
||||
@@ -26,13 +28,13 @@ for (let i = 1; i <= 100; i++) {
|
||||
}
|
||||
```
|
||||
|
||||
You have already hit a problem, and you have not even finished writing the code yet. But if you had worked out the logic first, you would have caught this issue before you ever touched your keyboard.
|
||||
You have already hit a problem, and you haven't even finished writing the code yet! If you had worked out the logic *first*, instead of jumping right into code, you would have been able to identify this problem without mucking around with the syntax.
|
||||
|
||||
## The Algorithmic Thinking Approach
|
||||
|
||||
Instead of starting with code, start with plain English. Write out your instructions step-by-step, as if you were explaining to a very literal, very stupid toddler who will do exactly what you say and nothing more.
|
||||
Instead of starting with code, start with plain language. Write out your instructions. Do so one step at a time, as if you were explaining to Naomi (who will do exactly what you say and nothing more).
|
||||
|
||||
Let us use FizzBuzz as an example. Here is how I would break it down:
|
||||
Let's use FizzBuzz as an example. Here is how I would break it down:
|
||||
|
||||
1. First, I look at the number.
|
||||
2. Is the number divisible by three?
|
||||
@@ -124,7 +126,7 @@ xxxxxxx
|
||||
xxxxxxxxx
|
||||
```
|
||||
|
||||
But that is not a pyramid! A pyramid should be centered, like:
|
||||
But that is not a pyramid! A pyramid should be centred, like:
|
||||
|
||||
```
|
||||
x
|
||||
@@ -134,7 +136,7 @@ But that is not a pyramid! A pyramid should be centered, like:
|
||||
xxxxxxxxx
|
||||
```
|
||||
|
||||
The instructions were missing a crucial detail: the spacing. But more importantly, they were not precise enough. "Add two more of the same single string beside it" - beside what? Where? The instructions assumed I would understand the intent, but a computer (or a very literal person following instructions) would not.
|
||||
The instructions were missing a crucial detail: the spacing. But more importantly, they were imprecise. "Add two more of the same single string beside it" - beside what? Where? The instructions assumed I would understand the intent, but a computer (or a very literal Naomi following instructions) would not.
|
||||
|
||||
After several iterations, we refined the instructions to be precise:
|
||||
|
||||
@@ -160,30 +162,142 @@ Let us go back to the pyramid example. We have our logic:
|
||||
3. Print the spaces, then the characters.
|
||||
4. Move to the next row.
|
||||
|
||||
Now we can think about the code structure:
|
||||
Now we can think about the code structure.
|
||||
|
||||
First, let's define our function:
|
||||
|
||||
```javascript
|
||||
function pyramid(characterToBuildPyramidWith, numOfRows) {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
What are our steps?
|
||||
|
||||
- We need a loop to iterate through rows.
|
||||
- For each row, we need to calculate spaces (which decrease as rows increase).
|
||||
- For each row, we need to calculate characters (which increase as rows increase).
|
||||
- We need to print the combination.
|
||||
- For each row, we gotta know how many spaces to use. We use less spaces in each row.
|
||||
- For each row, we gotta know how many characters to use. We use more characters in each row.
|
||||
- Finally, print our result.
|
||||
|
||||
The code almost writes itself once the logic is clear:
|
||||
Okay, let's create a loop to iterate through the number of rows. Sounds like a great usecase for a standard `for` loop.
|
||||
|
||||
```javascript
|
||||
function pyramid(characterToBuildPyramidWith, numOfRows) {
|
||||
for (let row = 0; row < numOfRows; row++) {
|
||||
const spaces = " ".repeat(numOfRows - row - 1);
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We're using `row` instead of `i`, so it's less confusing.
|
||||
|
||||
Now for each row (so each iteration), we gotta know how many spaces to use. Thankfully, we've already sorted that out in our logic:
|
||||
|
||||
> Add a number of spaces equal to the integer
|
||||
> Write the whole space and string again from the last row, get rid of one space again
|
||||
|
||||
So we start with `numOfRows` spaces, and for each iteration we can decrement the number of spaces by one. I think, then, that we could do `numOfRows - row`. Let's put that in a variable so we don't lose track.
|
||||
|
||||
```javascript
|
||||
function pyramid(characterToBuildPyramidWith, numOfRows) {
|
||||
for (let row = 0; row < numOfRows; row++) {
|
||||
const spaces = " ".repeat(numOfRows - row);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Alright, now the number of characters. Again, we can refer back to our paper logic:
|
||||
|
||||
> Write the same spaces string from before again, but get rid of one space, and write the string.
|
||||
> Write the whole space and string again from the last row, get rid of one space again, and add two more of the same string.
|
||||
|
||||
Okay, so we start with one character, and add two more for every iteration. That would be... `row` times two, but add one to account for the initial character.
|
||||
|
||||
|
||||
```javascript
|
||||
function pyramid(characterToBuildPyramidWith, numOfRows) {
|
||||
for (let row = 0; row < numOfRows; row++) {
|
||||
const spaces = " ".repeat(numOfRows - row);
|
||||
const characters = characterToBuildPyramidWith.repeat(row * 2 + 1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Finally, our last step:
|
||||
|
||||
> Finally, print our result.
|
||||
|
||||
We can print things with a `console.log` statement. Let's print our spaces followed by our characters.
|
||||
|
||||
```javascript
|
||||
function pyramid(characterToBuildPyramidWith, numOfRows) {
|
||||
for (let row = 0; row < numOfRows; row++) {
|
||||
const spaces = " ".repeat(numOfRows - row);
|
||||
const characters = characterToBuildPyramidWith.repeat(row * 2 + 1);
|
||||
console.log(spaces + characters);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
But notice: I did not write this code until I had worked through the logic step-by-step. I knew exactly what I needed to calculate and why, because I had already tested the logic manually.
|
||||
Time to double check our work! Let's call our function:
|
||||
|
||||
```javascript
|
||||
function pyramid(characterToBuildPyramidWith, numOfRows) {
|
||||
for (let row = 0; row < numOfRows; row++) {
|
||||
const spaces = " ".repeat(numOfRows - row);
|
||||
const characters = characterToBuildPyramidWith.repeat(row * 2 + 1);
|
||||
console.log(spaces + characters);
|
||||
}
|
||||
}
|
||||
|
||||
pyramid("x", 5);
|
||||
```
|
||||
|
||||
Checking the console, I see:
|
||||
|
||||
```txt
|
||||
x
|
||||
xxx
|
||||
xxxxx
|
||||
xxxxxxx
|
||||
xxxxxxxxx
|
||||
```
|
||||
|
||||
That looks like a pyramid! But hang on... It looks like we've shifted it one space too far. Let's go back to our logic on paper, because our logic is off (so we don't want to touch the code yet).
|
||||
|
||||
1. Look at the string. It is what we want the pyramid to be built by.
|
||||
2. Look at the integer. It is the amount of rows we want.
|
||||
3. Add a number of spaces equal to the integer, and then write the string.
|
||||
4. Go to the next line.
|
||||
5. Write the same spaces string from before again, but get rid of one space, and write the string.
|
||||
6. Add two more of the same single string beside it.
|
||||
7. Write the whole space and string again from the last row, get rid of one space again, and add two more of the same string.
|
||||
8. Repeat step 7 until you have the same number of rows as the integer.
|
||||
|
||||
AHA! Our issue is in step 3.
|
||||
|
||||
> 3. Add a number of spaces equal to the integer, and then write the string.
|
||||
|
||||
By adding the number of spaces equal to the integer, we've failed to account for the initial pyramid character. Essentially, we need to add one less space.
|
||||
|
||||
So we update our logic **first**:
|
||||
|
||||
1. Look at the string. It is what we want the pyramid to be built by.
|
||||
2. Look at the integer. It is the amount of rows we want.
|
||||
3. Add a number of spaces equal to the integer **less one**, and then write the string.
|
||||
4. Go to the next line.
|
||||
5. Write the same spaces string from before again, but get rid of one space, and write the string.
|
||||
6. Add two more of the same single string beside it.
|
||||
7. Write the whole space and string again from the last row, get rid of one space again, and add two more of the same string.
|
||||
8. Repeat step 7 until you have the same number of rows as the integer.
|
||||
|
||||
|
||||
|
||||
## When Logic Breaks During Coding
|
||||
|
||||
Here is a scenario that happens all the time: you have worked out your logic, tested it manually, and it looks perfect. You start translating it to code, and halfway through, you realize something does not make sense. Maybe you cannot figure out how to express a particular step. Maybe you discover an edge case you did not consider. Maybe the logic just... does not work the way you thought it would.
|
||||
I see it all the time. You have worked out your logic, tested it manually, and it looks perfect. You start translating it to code, and halfway through, you realize it's not perfect at all.
|
||||
|
||||
Maybe you cannot figure out how to achieve a specific step. Maybe you discover an edge case you did not consider. Maybe the logic just... does not work the way you thought it would.
|
||||
|
||||
**Stop coding immediately.**
|
||||
|
||||
@@ -203,6 +317,33 @@ Test it manually: if the integer is 5, I start with 5 spaces. Then I go to the n
|
||||
|
||||
Now you can go back to your code with clarity. You know that for row 0, you need `numOfRows - 0 - 1` spaces (which is 4 for 5 rows). For row 1, you need `numOfRows - 1 - 1` spaces (which is 3). The pattern is clear because you worked it out in logic first.
|
||||
|
||||
Okay, pretend we've tested our change manually (I am sparing you from reading through that process again), and it works. Now we can update our code to reflect our logic change:
|
||||
|
||||
```javascript
|
||||
function pyramid(characterToBuildPyramidWith, numOfRows) {
|
||||
for (let row = 0; row < numOfRows; row++) {
|
||||
// Notice how this is the ONLY change I made. We aren't changing anything that isn't updated in the logic on paper.
|
||||
const spaces = " ".repeat(numOfRows - row - 1);
|
||||
const characters = characterToBuildPyramidWith.repeat(row * 2 + 1);
|
||||
console.log(spaces + characters);
|
||||
}
|
||||
}
|
||||
|
||||
pyramid("x", 5);
|
||||
```
|
||||
|
||||
And we get:
|
||||
|
||||
```txt
|
||||
x
|
||||
xxx
|
||||
xxxxx
|
||||
xxxxxxx
|
||||
xxxxxxxxx
|
||||
```
|
||||
|
||||
**WE'VE DONE IT!!!!!**
|
||||
|
||||
The key principle here is: **if you discover a logic problem while coding, you have not discovered a coding problem. You have discovered that your logic was incomplete.** Fix the logic first, test it manually, and then return to the code.
|
||||
|
||||
This might feel inefficient. You might think "I am so close, let me just fix this one thing in code." But I promise you: fixing logic in code is like trying to repair the foundation of a house while you are painting the walls. It will not work, and you will make a bigger mess.
|
||||
@@ -223,13 +364,14 @@ When you think algorithmically first, you gain several advantages:
|
||||
|
||||
## The Takeaway
|
||||
|
||||
The next time you sit down to solve a coding problem, resist the urge to immediately start typing. Instead:
|
||||
The next time you have to write some code, don't write the code! Do this:
|
||||
|
||||
1. Write out your logic in plain English, step-by-step.
|
||||
2. Test that logic manually with several examples.
|
||||
3. Refine your logic until it works perfectly.
|
||||
4. **Only then** translate it into code.
|
||||
2. Test that logic by hand, using multiple test cases.
|
||||
3. Ideally, you've touched every "branch" in your logical breakdown.
|
||||
3. Edit and adjust the logic when test cases fail.
|
||||
4. Once all of your manual test cases pass your hand-written logic, you can finally begin translating it into code.
|
||||
|
||||
You will find that your code is cleaner, your bugs are fewer, and your problem-solving skills are stronger. And hey - if you can explain your logic to me in plain English and it works, then translating it to code is just a matter of syntax. And syntax is the easy part!
|
||||
|
||||
> đź’ˇ Remember: computers are really stupid toddlers who will do only and exactly what you say. Be precise, be thorough, and test your logic before you write your code.
|
||||
> đź’ˇ Remember: computers are children who will do only and exactly what you say. Be precise, be thorough, and test your logic before you write your code.
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
---
|
||||
title: "Living With Mental Illness"
|
||||
date: "2026-02-24"
|
||||
summary: "An honest account of my journey with schizophrenia, ADHD, anxiety, depression, insomnia, and everything that comes with them."
|
||||
---
|
||||
|
||||
Content warning: this article discusses suicide attempts, psychosis, self-medication with alcohol, and chronic illness. Please take care of yourself.
|
||||
|
||||
---
|
||||
|
||||
I have a lot of diagnoses. Schizophrenia. ADHD. Anxiety. Depression. Insomnia. Nerve damage. A heart condition. Lumbar spine degeneration. Diverticulosis. Some of those are mental health conditions. Some are physical. Most of them have some impact on the others. All of them are part of who I am.
|
||||
|
||||
I'm writing this because I don't see a lot of people talking about mental illness honestly - especially not schizophrenia, which carries more stigma than many other diagnoses. I want to change that, at least in my small corner of the internet. So here it is: my story, as openly as I can tell it.
|
||||
|
||||
## It Started When I Was Sixteen
|
||||
|
||||
Around the age of sixteen, my hallucinations got bad enough that I attempted suicide.
|
||||
|
||||
That's not an easy sentence to write. But it's the truth, and the truth is what this article is for.
|
||||
|
||||
The hallucinations were both auditory and visual. And the worst of them had a name: Ragnarok. He was a persistent hallucination - a demon who had his own identity, his own voice, and a singular purpose of feeding me negative thoughts, constantly. That was probably the worst period of my life. I was at my lowest point, drowning in something I didn't have a name for yet.
|
||||
|
||||
That's how I ended up in therapy and, eventually, with a diagnosis of schizophrenia.
|
||||
|
||||
## The Diagnosis
|
||||
|
||||
Having a name for what was happening was a relief. Finally, there was an explanation. But it was also terrifying.
|
||||
|
||||
> There is a *lot* of stigma around schizophrenia. Most people's understanding of it comes from movies and TV, and those portrayals are... not great.
|
||||
|
||||
The first medication they put me on was Seroquel. It worked - in the sense that it quieted Ragnarok and brought the hallucinations down. But the side effects were brutal. I felt like a complete zombie. Not like a person, just like a shell going through the motions. That's not living.
|
||||
|
||||
So I did what a lot of people do when treatment feels worse than the illness: I stopped going to therapy. I couldn't sustain it. And without that support, I just... struggle bussed. For years.
|
||||
|
||||
## The Retail Years
|
||||
|
||||
I spent a long time working in retail, and I won't mince words: it was miserable. The environment was high-stress, high-pressure, and absolutely not designed for someone managing a chaotic brain. The hallucinations never fully went away during that period - they just became the background noise of my life. I self-medicated with alcohol, because I couldn't sleep without it and I didn't know what else to do.
|
||||
|
||||
Looking back, the insomnia and the schizophrenia were feeding each other in a vicious loop. Sleep deprivation makes psychotic symptoms worse. Being symptomatic made it harder to sleep. I couldn't fall asleep, couldn't stay asleep, and was pouring absurd amounts of alcohol into myself to try to bridge the gap.
|
||||
|
||||
I'm not proud of that period. But I also don't think past-me deserves judgement for it. She was doing what she could to survive.
|
||||
|
||||
## 2020: The Year Everything Shifted
|
||||
|
||||
At the end of March 2020, I left my retail job. I had a decent nest egg - unemployment settlement, cashed out pension - and my plan was to take six months off, play video games, and then eventually go find work in Human Resources.
|
||||
|
||||
I got bored after two weeks.
|
||||
|
||||
I'd always loved tech, so I figured learning to code might be a fun hobby. I started working through freeCodeCamp, and something clicked almost immediately. It was genuinely fun. And then my ADHD brain - which I wouldn't be diagnosed with for another year - decided it had found its new obsession.
|
||||
|
||||
I was spending 10 to 12 hours a day, every single day, learning to code. I hit burnout hard in August, took a couple of weeks off, and then picked it right back up. By the end of 2020, what had started as a hobby had become the foundation of an entirely new career.
|
||||
|
||||
But here's the thing that mattered most: once I left that retail environment, my major hallucinations subsided significantly. The change in stress levels, the change in environment, the removal of that constant grinding pressure - it made a real difference. Ragnarok faded. The demons got quieter.
|
||||
|
||||
## Coming Out
|
||||
|
||||
In January 2022, I came out as transgender.
|
||||
|
||||
It was, honestly, a lot of anxiety at first. Coming out is not a small thing - there's vulnerability and fear baked into every step of it. But I started HRT in June 2022, and fairly quickly after that, my mental health started to genuinely improve. Not just stabilise - *improve*. There's something about finally being yourself, in your own body, that has effects that ripple out into everything else.
|
||||
|
||||
Transition has been one of the best things I've ever done for my mental health. I didn't expect that going in, but here we are.
|
||||
|
||||
## The ADHD Revelation
|
||||
|
||||
In 2021, I was diagnosed with ADHD.
|
||||
|
||||
My reaction was essentially: *oh yeah, that makes all the sense.*
|
||||
|
||||
I'd had it my whole life. The hyperfixation on coding. The years of inconsistent school performance. The manic episodes and tendencies that nobody could quite explain. The difficulty maintaining routines, the difficulty stopping once I'd started something interesting.
|
||||
|
||||
And the memories. My brain, it turns out, makes up memories. I can have vivid, detailed recollections of things that never happened - events I would swear on my life occurred, that everyone around me will tell you simply didn't. That's not something most people associate with ADHD, but it's a real and disorienting part of how my working memory functions (or doesn't). Growing up, I just thought something was wrong with me in a way that had no name.
|
||||
|
||||
Going undiagnosed for twenty-nine years meant decades of struggles that had no explanation. My own mother used to describe me as "spazztic." That word carries weight - the way people around you name your chaos when they don't understand it, when *you* don't understand it. You just know you're different and you don't know why.
|
||||
|
||||
Getting the diagnosis was one of those bittersweet relief moments. Yes, it's good to finally know. And also: wow, that would have been useful information thirty years ago.
|
||||
|
||||
## The Full Picture
|
||||
|
||||
The anxiety and depression came bundled in with everything else - the depression especially feels like it's been there as long as the schizophrenia, all tangled up together. The anxiety followed a few years later. Both are managed with medication. I'm on, as I affectionately describe it, a crap ton of medication.
|
||||
|
||||
The insomnia has also been with me for most of my life. I can't fall asleep. I can't stay asleep. These days I'm on prescription medication that helps considerably, and that's made a real difference to everything else - because when sleep deprivation is feeding your other conditions, getting sleep under control has knock-on effects.
|
||||
|
||||
Then there are the physical conditions. Diverticulosis is newer - the dietary changes have been a struggle, giving up foods I love for health reasons is never easy. But the other stuff: nerve damage, a heart condition, lumbar spine degeneration. Those are harder to sit with emotionally.
|
||||
|
||||
> Those conditions aren't going to get better. And if they get worse, my quality of life will probably tank. That's genuinely terrifying to live with.
|
||||
|
||||
Chronic and degenerative conditions carry their own mental and emotional weight that's separate from anything else on this list. The uncertainty, the anticipatory grief for capabilities you might lose - it's its own kind of burden.
|
||||
|
||||
## Tech Has Been Different
|
||||
|
||||
I want to be clear that tech is not a paradise for people with disabilities or mental health conditions. I've faced discrimination. I've had clients who were less than understanding of my erratic, ADHD-driven schedule. I worked for one employer that was very much a "good ol' boys" club - where every female employee, myself included, had our ideas dismissed and got steamrolled in every meeting.
|
||||
|
||||
But overall? Tech has been significantly better for me than retail was. My employers have been more flexible, more accommodating, and more willing to work with the reality of how my brain functions.
|
||||
|
||||
When it comes to disclosure, I don't lead with my diagnoses in interviews. I'm an open book and I'll share whatever feels relevant, but I've rarely needed to formally request ADA accommodations - things tend to just get worked out naturally. Mostly it comes up on its own, especially after a rough few days. And in tech, I've found that most employers have been pretty chill about it. That's not universal, as the discrimination I mentioned proves, but it's been the norm.
|
||||
|
||||
## Remote Work Changed Everything
|
||||
|
||||
If I had to name the single biggest structural factor in my mental health stability as a tech worker, it would be remote work. Not therapy. Not medication (though those matter enormously). Remote work.
|
||||
|
||||
Working from home means I get to control my entire environment. I blast my music. I take breaks to play with my cats. I work whatever erratic hours align with how my brain is functioning that day - and I make up for the scattered hours by working stupidly long ones when I'm in flow.
|
||||
|
||||
What a bad day looks like depends on which condition is causing it. An ADHD day means I'm manic and scattered, constantly switching between tasks, probably saying the most unhinged things in Slack. An insomnia day means I take a slow morning and ease in. A depression or schizophrenia day - which are rare now, but still happen - means I just take the day off, full stop. I can switch my notifications to my phone, step away from the desk, decompress, and come back when I'm ready. In an office, none of that would be possible.
|
||||
|
||||
And then there's masking. In an office environment, there's an enormous amount of pressure to perform neurotypicality all day - to look busy, to hold it together visibly, to hide the chaos. At home, that's just not a thing. I try to be put together when I'm on camera in a meeting. The rest of the time?
|
||||
|
||||
> I get to be my unapologetically authentic self. And that is when I do my best work.
|
||||
|
||||
## What It Actually Looks Like Now
|
||||
|
||||
Day-to-day, schizophrenia for me mostly means corner-of-the-eye visual hallucinations and random sounds. Most of the time, I can tell they aren't real. I know the difference between what's actually there and what my brain is generating. That ability - to recognise and reality-check - is something I did not have at sixteen.
|
||||
|
||||
The ADHD, even medicated, is a constant presence. My executive function is still rubbish. I have calendar notifications set for things like taking a shower and eating meals - not as suggestions, but as genuine reminders I actually need. My sister reminds me to drink water. The external scaffolding I've built around myself isn't optional: it's how I function. Without the ticketing system, the calendar, the reminders, the routines - things don't get done.
|
||||
|
||||
I'm still working on finding the right medication cocktail, which is its own ongoing saga. As of right now, my ADHD medications were just adjusted and I am an absolute mess - which is why I took last week off work. My sister helps me enormously. Having that support network matters more than I can express.
|
||||
|
||||
Managing mental illness is not a destination. It's not something you solve and then it's done. It's ongoing. It's a constant, sometimes frustrating, always-adjusting process of figuring out what works right now, because what works right now might not be what worked six months ago.
|
||||
|
||||
## What I Wish People Understood About Schizophrenia
|
||||
|
||||
The media portrayal of schizophrenia is so wildly divorced from the actual lived experience that it almost doesn't bear comparison.
|
||||
|
||||
It is not constant, dramatic hallucinations. It is not "tripping balls." It is not the dangerous, unpredictable violence that gets portrayed in horror movies.
|
||||
|
||||
> Schizophrenia, for me, is an overall lack of grasp on reality. It's the world not quite holding together the way it should. It's knowing, intellectually, that something isn't real while your brain insists it is.
|
||||
|
||||
It looks different for different people. But it does not look like what the movies show you.
|
||||
|
||||
## What I Wish People Knew About ADHD
|
||||
|
||||
People hear "ADHD" and think it means you can't focus. That's not quite right.
|
||||
|
||||
The more accurate description is that your brain does not have a volume dial for attention. It has an on/off switch, and you don't control it. When something captures your interest, the switch flips on and you are *locked in* - sometimes for hours, sometimes to the exclusion of literally everything else. When something doesn't capture your interest, no amount of willpower will flip that switch. The attention just isn't there.
|
||||
|
||||
But it goes so far beyond focus. ADHD is a full executive function disorder. It looks like this:
|
||||
|
||||
> "Okay, I need to do the thing. Wait, what was I doing? Oh right, I was going to check Bluesky really quick. ...Forty minutes later... Wait, no, I need to do the thing. Actually, I should have a smoke first. Wait, what was I doing? Oh, I gotta pee."
|
||||
|
||||
ADHD is spilling coffee all over yourself because you forgot you were holding the cup. It's knowing there are exactly 46 slats in your blinds because you counted them three times during a meeting. It's setting your phone down on your desk directly in front of you, and then spending fifteen minutes looking for your phone.
|
||||
|
||||
> It's not laziness. It's not a lack of trying. It's a brain that is genuinely fighting against you on the most basic task management, every single day.
|
||||
|
||||
## The Upsides (Yes, There Are Some)
|
||||
|
||||
I said earlier that my success has come *because* of my conditions, not in spite of them. Let me be specific about what I mean.
|
||||
|
||||
My ADHD has made me the absolute queen of writing tickets. If something isn't in a ticket, it does not exist in my brain - it will be lost to the void. So I ticket *everything*. Every task, every bug, every idea, every follow-up. My Asana board is colour-coded, sorted by due date, grouped by project, and it is genuinely beautiful. My colleagues can pull it up at any moment and get a complete picture of everything I'm working on and when it's due.
|
||||
|
||||
That system didn't come from discipline. It came from necessity - because ADHD left me no other choice.
|
||||
|
||||
And my anxiety? The crippling, exhausting fear of failure and of letting people down? It means I am *constantly* asking for feedback on my performance. Constantly looking for ways to grow. Constantly trying to be better. The fear that drives the anxiety is real and unpleasant, but the behaviour it produces has made me someone who actively shapes their own professional development rather than waiting to be told how they're doing.
|
||||
|
||||
Your conditions are not just obstacles. They shaped the way you work, the way you think, and the adaptations you've built. Those adaptations often turn out to be genuine strengths.
|
||||
|
||||
## To Anyone Who Is Struggling
|
||||
|
||||
If you're reading this and you recognise yourself somewhere in it - the late diagnoses, the wrong medications, the self-medicating, the years of white-knuckling it through environments that weren't built for you - I want you to know this:
|
||||
|
||||
You can still find success. Not *in spite of* your mental illnesses, but *because* of them.
|
||||
|
||||
The hyperfixation that made me lose twelve hours to coding every day? That's ADHD. That's also how I built a career from scratch in under a year. The resilience I have, the depth of empathy I carry for people who are struggling, the way I understand what rock bottom actually looks like - those things come directly from everything I've been through.
|
||||
|
||||
Your brain is not broken. It's different. And different, with the right circumstances and the right support, can be extraordinary.
|
||||
|
||||
I'm still figuring it out. I might always be figuring it out. That's okay.
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
title: "a dev community where people are scared to ask questions is not a community~"
|
||||
date: "2026-06-10"
|
||||
summary: "if people are scared to ask questions, it is not a community."
|
||||
---
|
||||
|
||||
a dev community where people are scared to ask questions is not a community~
|
||||
|
||||
i run the community spaces for a charity in the developer education space if people are not comfortable asking questions the entire thing falls apart
|
||||
|
||||
so like it is not just making people feel welcome and comfortable and happy but it is also ensuring that the friction of participating does not outweigh the benefits
|
||||
|
||||
in our industry it is especially important to be cognisant of this because like we have a history of gatekeeping and treating knowledge like its wealth or something yknow how sometimes the way new developers are met is with condescension
|
||||
|
||||
anyway communities that wanna be chill vibes still end up with vibes that are kinda hostile towards the next generation a lil so i encourage you to keep that in mind~
|
||||
|
||||
so how do we fix it naomi well that is a very good question lets do some ideation!!!
|
||||
|
||||
my first thought is that having a strong (volunteer) moderation team who can help address the more hostile or aggressive developer feedback to ease some of the internal tensions that we face would be a huge boon
|
||||
|
||||
strong and explicit community policy is a must like you gotta have a good code of conduct and such but also your team need to *embody* that policy they gotta walk the walk with consistent and effective moderation and talk the talk in the way they conduct their interactions in the community
|
||||
|
||||
depending on how many your community is you may benefit from having dedicated spaces for the newer generation of developers to ask their questions in a judgement free space without having to see the seniors asking much more complex questions if that makes sense
|
||||
|
||||
naomi we have kpis and some other thing we have to do numbers!!!! okay that is fine let me help you do some numbers~
|
||||
|
||||
first one is member retention - more specifically, what percentage of your members who ask their first help question return to ask another????
|
||||
|
||||
second one is community driven engagement - are the help questions being answered by community members before you can even respond?????
|
||||
|
||||
and how about your diversity in participants especially across skill levels (and marginalised identities of course) are the folks who are oft under-represented more equally distributed in your demographics?????????
|
||||
|
||||
without these in place your community will never be able to thrive~
|
||||
+47
-12
@@ -1,11 +1,11 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@import "tailwindcss";
|
||||
|
||||
* {
|
||||
font-family: "Vampyr", monospace;
|
||||
@theme {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
h1 {
|
||||
@apply text-4xl;
|
||||
}
|
||||
@@ -39,18 +39,53 @@ blockquote p {
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border: 2px dotted;
|
||||
border-left: 5px solid var(--accent);
|
||||
box-shadow: inset 4px 0 10px -4px var(--accent);
|
||||
padding-left: 1rem;
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.text-balance {
|
||||
text-wrap: balance;
|
||||
}
|
||||
}
|
||||
|
||||
figcaption {
|
||||
@apply text-sm;
|
||||
@apply text-center;
|
||||
@apply italic;
|
||||
}
|
||||
|
||||
pre {
|
||||
@apply text-left;
|
||||
@apply bg-gray-100;
|
||||
@apply p-2;
|
||||
@apply rounded-md;
|
||||
@apply border;
|
||||
@apply border-gray-300;
|
||||
@apply overflow-x-auto;
|
||||
@apply whitespace-pre-wrap;
|
||||
@apply break-words;
|
||||
@apply text-sm;
|
||||
@apply font-mono;
|
||||
}
|
||||
|
||||
code:not(pre code) {
|
||||
@apply text-sm;
|
||||
@apply font-mono;
|
||||
@apply bg-gray-100;
|
||||
@apply p-1;
|
||||
@apply rounded-md;
|
||||
@apply border;
|
||||
@apply border-gray-300;
|
||||
@apply overflow-x-auto;
|
||||
@apply whitespace-pre-wrap;
|
||||
@apply break-words;
|
||||
}
|
||||
}
|
||||
|
||||
.is-dark blockquote,
|
||||
.is-dark blockquote p {
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.text-balance {
|
||||
text-wrap: balance;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-14
@@ -3,19 +3,14 @@
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
import { Inter } from "next/font/google";
|
||||
import Script from "next/script";
|
||||
import type { Metadata } from "next";
|
||||
import type { JSX, ReactNode } from "react";
|
||||
// eslint-disable-next-line import/no-unassigned-import -- Import global styles.
|
||||
import "./globals.css";
|
||||
|
||||
// eslint-disable-next-line new-cap -- This is a function call.
|
||||
const inter = Inter({ subsets: [ "latin" ] });
|
||||
|
||||
const metadata: Metadata = {
|
||||
description:
|
||||
"The personal musings of a transfem software engineer.",
|
||||
description: "The personal musings of a transfem software engineer.",
|
||||
openGraph: {
|
||||
images: "https://cdn.nhcarrigan.com/og-image.png",
|
||||
},
|
||||
@@ -41,6 +36,14 @@ const RootLayout = ({
|
||||
}>): JSX.Element => {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link href="https://cdn.nhcarrigan.com/logo.png" rel="icon" sizes="any" />
|
||||
<link
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css"
|
||||
precedence="default"
|
||||
rel="stylesheet"
|
||||
></link>
|
||||
</head>
|
||||
<Script
|
||||
async={true}
|
||||
defer={true}
|
||||
@@ -48,14 +51,7 @@ const RootLayout = ({
|
||||
strategy={"afterInteractive"}
|
||||
type="text/javascript"
|
||||
></Script>
|
||||
<link
|
||||
href="https://cdn.nhcarrigan.com/logo.png"
|
||||
rel="icon"
|
||||
sizes="any"
|
||||
/>
|
||||
<body className={inter.className}>
|
||||
{children}
|
||||
</body>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import Markdown from "react-markdown";
|
||||
import rehypeHighlight from "rehype-highlight";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import type { JSX } from "react";
|
||||
@@ -34,7 +35,7 @@ const Page = async({
|
||||
<h2 className="text-center">{post.data.summary}</h2>
|
||||
<p className="text-center">{`A ${post.data.readtime}.`}</p>
|
||||
<Rule />
|
||||
<Markdown rehypePlugins={[ rehypeRaw ]} remarkPlugins={[ remarkGfm ]}>
|
||||
<Markdown rehypePlugins={[ rehypeRaw, rehypeHighlight ]} remarkPlugins={[ remarkGfm ]}>
|
||||
{post.content}
|
||||
</Markdown>
|
||||
<Rule />
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
|
||||
export default {
|
||||
content: [
|
||||
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
background: "var(--background)",
|
||||
foreground: "var(--foreground)",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
} satisfies Config;
|
||||
+19
-5
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
@@ -11,7 +15,7 @@
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
@@ -19,9 +23,19 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
".next/dev/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user