In my day-job, I'm a leader of{' '} - + Engineering Practice Improvement - + . I help teams build better software - faster. We can talk more about my feelings on all of that soon @@ -408,6 +408,13 @@ export default function AgentCoordinationPost() {
diff --git a/app/(main)/about/opengraph-image.tsx b/app/(main)/about/opengraph-image.tsx
new file mode 100644
index 0000000..2bccb04
--- /dev/null
+++ b/app/(main)/about/opengraph-image.tsx
@@ -0,0 +1,10 @@
+import { OG_SIZE, ogCard } from '../../../lib/og-image'
+
+export const dynamic = 'force-static'
+export const alt = 'Jordan Winters - Software Consultant, Minneapolis'
+export const size = OG_SIZE
+export const contentType = 'image/png'
+
+export default function OpengraphImage() {
+ return ogCard('Jordan Winters', 'Software Consultant · Minneapolis')
+}
diff --git a/app/(main)/about/page.test.tsx b/app/(main)/about/page.test.tsx
new file mode 100644
index 0000000..bece186
--- /dev/null
+++ b/app/(main)/about/page.test.tsx
@@ -0,0 +1,73 @@
+import { axeTest, render, screen } from 'lib/test-utils'
+import { describe, expect, it } from 'vitest'
+import AboutPage from './page'
+
+describe('About Page', () => {
+ it('names Jordan Winters with the Minneapolis base and experience claim', () => {
+ render(
+ I live and work in Minneapolis, and I've spent over a decade building software and
+ building the teams that build software. The short version: I led operations through an
+ organizational doubling at an ad-tech startup, spent five and a half years as a Staff
+ DevOps Engineer at NerdWallet (including steering a cloud cost journey that took over
+ $1.5M out of yearly spend), founded an Observability practice as an Engineering Manager at
+ a Fortune 500 financial services company, and took an AI-native startup from empty
+ repository to public beta in six months as its founding engineer. Bidwell Consulting is
+ where I now do that work directly for companies across the Twin Cities metro, and remotely
+ everywhere else.
+
+ You can verify most of this the same way I would:{' '}
+
+ LinkedIn
+ {' '}
+ for the career,{' '}
+
+ GitHub
+ {' '}
+ for the code, and my essay on{' '}
+
+ coordinating AI coding agents
+ {' '}
+ for how I think.
+
+ Solo by design - the person you meet on the discovery call designs the system, writes the
+ code, and answers the hard questions himself. No juniors to hand you off to.
+
+ When I'm not shipping software I'm usually making music - you can hear what that
+ sounds like on{' '}
+
+ SoundCloud
+
+ . Minneapolis is home, and the coffee-meeting offer is real.
+
+ Or just{' '}
+
+ get in touch
+ {' '}
+ - the discovery call is free.
+ About Jordan Winters
+
+ Hi, I'm Jordan
+ What I Believe
+
+
+ How I Work
+ Beyond Work
+ Work With Me
+
+ {serviceEntries.map(service => (
+
+
- {formatPostDate(post.publishedAt)} + + Jordan Winters + {' '} + · {formatPostDate(post.publishedAt)}
In my day-job, I'm a leader of{' '} - + Engineering Practice Improvement - + . I help teams build better software - faster. We can talk more about my feelings on all of that soon @@ -408,6 +408,13 @@ export default function AgentCoordinationPost() {
+ I help teams put this into practice - see{' '} + + AI & agent engineering consulting + + . +
) } diff --git a/app/(main)/blog/page.tsx b/app/(main)/blog/page.tsx index 46f530f..49509d5 100644 --- a/app/(main)/blog/page.tsx +++ b/app/(main)/blog/page.tsx @@ -5,7 +5,8 @@ import { formatPostDate, posts } from './posts' export const metadata: Metadata = { title: 'Blog', - description: 'Updates and insights from the Bidwell Consulting team.', + description: + 'Notes on software engineering, AI coding agents, and engineering practice from Jordan Winters, a software consultant in Minneapolis.', alternates: { canonical: '/blog' }, } @@ -29,6 +30,13 @@ export default function BlogPage() { ))} ++ Subscribe via{' '} + + RSS + + . +
) } diff --git a/app/(main)/blog/posts.ts b/app/(main)/blog/posts.ts index 1dae616..4e7061e 100644 --- a/app/(main)/blog/posts.ts +++ b/app/(main)/blog/posts.ts @@ -1,11 +1,13 @@ /** - * Blog post registry — the single source of truth for post metadata. + * Blog post registry - the single source of truth for post metadata. * Pure data with no imports: app/sitemap.ts consumes this and must stay * executable by tsx (health-check generation) outside the Next bundler. */ export interface Post { slug: string title: string + /** Search-targeted- With nearly 20 years of experience in professional development, I offer career coaching - for those navigating transitions, preparing for interviews, or figuring out their next - move. -
- -{service.description}
-{option.description}
-{faq.answer}
-- The best way to reach me is through LinkedIn. Send a message and we can set up a time to - talk. -
- - Connect on LinkedIn - -+ Email is best:{' '} + + {siteConfig.email} + + . LinkedIn works too - I read everything. +
+ ++ Every engagement starts with a free 30-minute conversation - no pitch. We'll talk + through what you're working on and whether I'm the right person to help. If + I'm not, I'll say so and point you somewhere better. +
++ Bidwell Consulting · Minneapolis, MN · Serving the Twin Cities metro · Remote-friendly +
+- Welcome to Bidwell Consulting, I look forward to working with you! Here, you can find my - thoughts on problem solving. -
++ I'm{' '} + + Jordan Winters + + , an independent software consultant in Minneapolis. I help companies design systems, ship + software, and build engineering practices that hold up - over a decade of building and + leading behind it. +
+ ++ {service.description} +
+ + ))} ++ Or browse{' '} + + all services + + . +
++ I coordinate coding agents to ship real software every day, not just advise on it, and I + publish{' '} + + how I coordinate AI coding agents + + . Bring AI into your engineering practice with someone who has already made it work in his + own. +
++ Based in Minneapolis and serving the Twin Cities metro - in person when it helps, remote + when it doesn't. +
++ Tell me what you're building, what's stuck, or where you want to be.{' '} + + Book a free discovery call + + , email{' '} + + {siteConfig.email} + + , or reach out on{' '} + + LinkedIn + + . +
+ Plenty of consultants advise on AI. I build with it daily, including the multi-agent + workflows that produce my own work, and I publish{' '} + + how I coordinate AI coding agents + {' '} + so you can judge the approach before you pay for it. Most recently I took an AI-native + platform from empty repository to public beta in six months, with a cost architecture that + held 90% gross margin on AI-heavy workloads. +
+ ++ Wiring large language models into products and workflows that already exist: document + processing, support triage, search and retrieval over your own data, drafting and + summarization inside the tools your team lives in. Scoped around evaluation and unit + economics from day one, so you know whether it works in production and what it costs per + request - not just whether it demos. +
++ Agents earn their keep on multi-step work: triaging queues, reconciling records, turning + documents and images into structured, queryable data. I design them with explicit + boundaries and human checkpoints wherever a mistake would actually cost you something. +
++ Coding agents are the biggest change to software delivery in a decade, and most teams get + mixed results because they adopted the tool without the practice. I help engineering teams + put the structure around Copilot- and Claude-class tools - review discipline, quality + gates, coordination patterns - so agents raise your team's output instead of your + incident count. Building that structure is what I do: I've founded an enterprise + Observability practice and stood up the delivery engine for a founding team, then handed + both off running. +
++ I approach AI projects pragmatically. It's spectacular at some jobs and confidently + wrong at others, and the expensive failures come from not knowing which is which. I start + small, measure real outcomes, design the data boundaries deliberately, and tell you when + the right answer is “don't use AI for this.” +
++ Twin Cities companies are past the demo phase. The question now is what AI actually + changes for their business. I meet Minneapolis-St. Paul clients in person for working + sessions and leadership briefings; the engineering itself runs remote, same as any modern + delivery. +
+{faq.answer}
++ Making AI adoption stick is a practice problem - see{' '} + + engineering practice improvement + + . If the system around the model needs building too, see{' '} + + software consulting + + . +
++ Tell me about the workflow you think AI could carry.{' '} + + Book a free discovery call + {' '} + - 30 minutes, no commitment. +
++ With over a decade in software and professional development, I coach engineers and tech + professionals navigating transitions, preparing for interviews, or figuring out their next + move. +
++ Based in Minneapolis - most coaching happens over video, so location never gets in the + way. +
++ or{' '} + + book a free discovery call + +
+{service.description}
+{option.description}
+{faq.answer}
++ Email{' '} + + {siteConfig.email} + + , reach me through LinkedIn, or{' '} + + book a free discovery call + {' '} + and we can set up a time to talk. +
+ + Connect on LinkedIn + ++ If you want the context first:{' '} + + more about my background + + . +
++ Helping engineering teams ship faster is the work I keep coming back to. I've founded + an enterprise Observability practice, rebuilt scrum processes that lifted sprint goal + completion by more than 30%, and stood up the delivery engine that carried a founding team + from first commit to public beta in six months. If your team is busy but delivery feels + slow, the problem is rarely effort - it's friction, and I know where to find it. +
+ ++ The whole path from idea to production: DevOps practices and pipeline health, agile + delivery that serves outcomes instead of ceremony, code ownership and review culture, and + the Product Operating Model that connects engineering work to things customers notice. + Teams should run experiments, own what they ship, and see their work matter. +
++ Assess: a few weeks watching how work actually flows, not how the wiki + says it flows. Recommend: a short, ranked list of changes with the + reasoning attached, never a hundred-page deck. Embed: I work alongside + the team while the changes take hold, because practice change that arrives by memo + doesn't survive the quarter. At one client that meant migrating a fragmented logging + estate to a single pane of glass while cutting ingest costs enough to make the migration + pay for itself. +
++ Lead time, deploy frequency, change-failure rate, time to recover - measured before and + after, so improvement is a fact rather than a feeling. I've run this playbook at + scale: sprint goal completion up more than 30%, mid-sprint additions cut in half. And the + AI-era addition: teams with their practices in order can adopt coding agents safely and go + genuinely faster. Teams without them just produce defects at higher velocity. +
++ Practice change sticks when someone is in the room. For Minneapolis-St. Paul teams I embed + on-site for the moments that matter: working sessions, retros, delivery reviews. + Everything else runs remote. Fully distributed org - the engagement runs remote just as + well. +
+{faq.answer}
++ If AI adoption is part of the change, see{' '} + + AI & agent engineering + + . For growth support for the engineers themselves, see{' '} + + career coaching + + . +
++ Tell me where delivery feels stuck and we'll dig into the friction together.{' '} + + Book a free discovery call + {' '} + - 30 minutes, no commitment. +
++ I'm Jordan Winters - an independent consultant with over a decade in software. Every + engagement is with me directly: the person you talk to on the discovery call is the person + who does the work. I'm based in Minneapolis and work with companies across the Twin + Cities metro, and remotely everywhere else. +
++ {service.description} +
+ + Learn more + + + ))} ++ Founders and CTOs of small-to-mid companies who need senior software judgment without an + agency's overhead. Engineering leaders at larger organizations who want delivery to + feel less stuck. And individual engineers working on their own careers. I'm one + person by design, which means one point of contact and no handoffs. +
++ Start with the{' '} + + free 30-minute discovery call + {' '} + and I'll point you to the right one. +
++ I'm Jordan Winters, an independent software consultant with over a decade of building + and leading: staff-level DevOps at a national fintech, platform builds from scratch, and + cloud architecture that holds up under real traffic and real budgets. I design systems and I + write the code. +
+ ++ If you're going from 0 to 1, I build the core infrastructure and development + environment for rapid iteration: cloud architecture on AWS or GCP, Terraform-managed with + environment isolation, CI/CD, observability, and cost models from day one. Most recently I + did exactly this as a founding engineer - empty repository to public beta in six months. +
++ Architecture reviews before you commit a year of budget. Build-versus-buy calls with the + trade-offs stated plainly. System design that starts from your constraints: team size, + budget, and what you can operate at 2 a.m. Not whatever's trending. +
++ Brittle deploys, sprawling cloud bills, legacy systems everyone is afraid to touch - this + is home turf. I've commodified compute hosting onto self-scaling container platforms + (cutting legacy costs 70%), shrunk build and deploy times by more than 75%, and steered a + multi-year cloud cost journey that took over $1.5M out of yearly spend. Modernization pays + for itself when you sequence it right. +
++ Three shapes: a fixed-scope assessment when you need clarity before + committing, a project when you need something built, or an ongoing{' '} + advisory arrangement when your team needs a senior technical voice on + call. Every engagement starts with a free 30-minute discovery call and a written scope. + You'll always know what you're paying for and what done looks like. +
++ I'm based in Minneapolis. For the parts of software work that go better in a room, + I'll come to you anywhere in the Minneapolis-St. Paul metro: architecture sessions, + whiteboarding, team workshops. The day-to-day build work runs remote, so distance never + slows a project down. +
+{faq.answer}
++ For LLM and coding-agent work, see{' '} + + AI & agent engineering + + . If the team is shipping slower than it should, see{' '} + + engineering practice improvement + + . +
++ Tell me what you're building or what's stuck.{' '} + + Book a free discovery call + {' '} + - 30 minutes, no commitment. +
+The Governed Swarm
A drop-in template for Claude Code that turns a single AI assistant into a coordinated - engineering team — with the guardrails to trust what it ships. + engineering team - with the guardrails to trust what it ships.
An unsupervised coding agent is a firehose: fast, confident, and indifferent to your - standards. The interesting problem isn't getting AI to write code — it's making the + standards. The interesting problem isn't getting AI to write code - it's making the output trustworthy. The framework's bet: treat the agent like an engineering organization, not an autocomplete.
@@ -308,7 +308,7 @@ export default function ClaudeAgenticFrameworkPage(): React.JSX.Element {Prose instructions are suggestions to a language model. The framework's sharpest idea is - admitting that — and pushing anything that must be true down the ladder until a machine + admitting that - and pushing anything that must be true down the ladder until a machine checks it.
@@ -360,7 +360,7 @@ export default function ClaudeAgenticFrameworkPage(): React.JSX.Element { This site is the lab
- bidwell.info runs on the framework it's describing — v3.1.0, checked into this
+ bidwell.info runs on the framework it's describing - v3.1.0, checked into this
repository's .claude directory. The
experiments hub you arrived from was specified in a PRD, architected in an ADR, and
built and reviewed by the swarm.
@@ -404,7 +404,7 @@ export default function ClaudeAgenticFrameworkPage(): React.JSX.Element {
The recommended install is a raw drop-in: clone the framework and run its init script
against your project. It sets up the .claude{' '}
- directory — commands, skills, agents, rules, hooks — and leaves the rest of your repo
+ directory - commands, skills, agents, rules, hooks - and leaves the rest of your repo
alone.
- Read the init script before you run it — the framework would tell you to do the same.
+ Read the init script before you run it - the framework would tell you to do the same.
Prefer a lighter footprint? Install it as a Claude Code plugin instead:{' '}
/plugin install agentic-framework@agentic-framework
The Sentiment Geoscope
- The Global Anxiety Map is a geospatial visualization of negative sentiment—specifically - "Anxiety" and "Uncertainty"—extracted from global news media. It acts as a "Geiger + The Global Anxiety Map is a geospatial visualization of negative sentiment - specifically + "Anxiety" and "Uncertainty" - extracted from global news media. It acts as a "Geiger counter" for geopolitical stability, highlighting regions where the language of fear is spiking.
diff --git a/app/(wide)/experiments/live-order-book/page.tsx b/app/(wide)/experiments/live-order-book/page.tsx index df0b7c5..b9e8d03 100644 --- a/app/(wide)/experiments/live-order-book/page.tsx +++ b/app/(wide)/experiments/live-order-book/page.tsx @@ -9,7 +9,7 @@ export default function LiveOrderBookPage() {The Market Depth Crumble
- This concept renders the limit order book as a physical structure—two opposing walls of + This concept renders the limit order book as a physical structure - two opposing walls of "Buy" and "Sell" volume. As trades occur, they are visualized as projectiles smashing into these walls, physically destroying the blocks, helping traders intuitively feel the "sell pressure" or "support." diff --git a/app/components/footer.test.tsx b/app/components/footer.test.tsx index a3a3174..dd2260f 100644 --- a/app/components/footer.test.tsx +++ b/app/components/footer.test.tsx @@ -1,43 +1,80 @@ -import { render, screen } from '@testing-library/react' -import { axeTest } from 'lib/test-utils' +import { axeTest, render, screen } from 'lib/test-utils' +import { describe, expect, it } from 'vitest' import Footer from './footer' describe('Footer Component', () => { - it('renders navigation links', () => { + it('links all four services', () => { render() - expect(screen.getByRole('link', { name: /linkedin/i })).toBeInTheDocument() - expect(screen.getByRole('link', { name: /github/i })).toBeInTheDocument() - expect(screen.getByRole('link', { name: /soundcloud/i })).toBeInTheDocument() + expect(screen.getByRole('link', { name: /software consulting/i })).toHaveAttribute( + 'href', + '/services/software-consulting' + ) + expect(screen.getByRole('link', { name: /ai & agent engineering/i })).toHaveAttribute( + 'href', + '/services/ai-consulting' + ) + expect(screen.getByRole('link', { name: /engineering practice improvement/i })).toHaveAttribute( + 'href', + '/services/engineering-practice-improvement' + ) + expect(screen.getByRole('link', { name: /career coaching/i })).toHaveAttribute( + 'href', + '/services/career-coaching' + ) }) - it('has correct href attributes', () => { + it('links the site pages including experiments', () => { render() - expect(screen.getByRole('link', { name: /linkedin/i })).toHaveAttribute( + expect(screen.getByRole('link', { name: /about/i })).toHaveAttribute('href', '/about') + expect(screen.getByRole('link', { name: /blog/i })).toHaveAttribute('href', '/blog') + expect(screen.getByRole('link', { name: /experiments/i })).toHaveAttribute( 'href', - 'https://www.linkedin.com/in/wintersjordan/' + '/experiments' ) - expect(screen.getByRole('link', { name: /github/i })).toHaveAttribute( - 'href', - 'https://github.com/dralgorhythm' - ) - expect(screen.getByRole('link', { name: /soundcloud/i })).toHaveAttribute( + expect(screen.getByRole('link', { name: /contact/i })).toHaveAttribute('href', '/contact') + }) + + it('links the contact email as mailto', () => { + render() + + expect(screen.getByRole('link', { name: /jordan@bidwell\.info/i })).toHaveAttribute( 'href', - 'https://soundcloud.com/dralgorhythm' + 'mailto:jordan@bidwell.info' ) }) - it('opens external links in new tab with security attributes', () => { + it('opens social links safely in a new tab', () => { render() - const links = screen.getAllByRole('link') - for (const link of links) { + const socials: [string, string][] = [ + ['linkedin', 'https://www.linkedin.com/in/wintersjordan/'], + ['github', 'https://github.com/dralgorhythm'], + ['soundcloud', 'https://soundcloud.com/dralgorhythm'], + ] + for (const [name, href] of socials) { + const link = screen.getByRole('link', { name: new RegExp(name, 'i') }) + expect(link).toHaveAttribute('href', href) expect(link).toHaveAttribute('target', '_blank') expect(link).toHaveAttribute('rel', 'noopener noreferrer') } }) + it('shows the NAP line exactly once, plain', () => { + render() + + expect( + screen.getAllByText(/bidwell consulting · minneapolis, mn · serving the twin cities metro/i) + ).toHaveLength(1) + }) + + it('is a labeled footer navigation landmark', () => { + render() + + expect(screen.getByRole('navigation', { name: /footer/i })).toBeInTheDocument() + }) + it('is accessible', async () => { const { container } = render() await axeTest(container) diff --git a/app/components/footer.tsx b/app/components/footer.tsx index 59912ea..7ef76c0 100644 --- a/app/components/footer.tsx +++ b/app/components/footer.tsx @@ -1,5 +1,22 @@ +import Link from 'next/link' import type React from 'react' +import { siteConfig } from '../../lib/site-config' +import { serviceEntries } from '../config/services' + +const siteLinks = [ + { name: 'About', href: '/about' }, + { name: 'Blog', href: '/blog' }, + { name: 'Experiments', href: '/experiments' }, + { name: 'Contact', href: '/contact' }, +] + +const socialLinks = [ + { name: 'linkedin', href: 'https://www.linkedin.com/in/wintersjordan/' }, + { name: 'github', href: 'https://github.com/dralgorhythm' }, + { name: 'soundcloud', href: 'https://soundcloud.com/dralgorhythm' }, +] + function ArrowIcon(): React.JSX.Element { return (