Skip to content

Commit 701d517

Browse files
committed
Hardcoded post -> md post rendered in jsx
1 parent 177793e commit 701d517

File tree

7 files changed

+1579
-308
lines changed

7 files changed

+1579
-308
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
title: "Building an AI-Native Ethereum Developer Stack"
3+
date: "February 2026"
4+
description: "How we're restructuring our Ethereum developer stack: Scaffold-ETH 2 and Speedrun Ethereum to be AI native."
5+
---
6+
7+
For years, we've been building our dev tools and learning materials primarily for humans. Docs explained what our toolkit did. We taught developers with guided, hands-on experiences. Extensions shipped as mergeable code.
8+
9+
But we're finding that this model gets a bit clunky when an AI agent is driving the keyboard.
10+
11+
Instead of just asking "how do we add AI to our tools" we started asking ourselves: what would our stack look like if we treated the AI as a primary user alongside the developer?
12+
13+
For us, that meant rethinking some of our core primitives rather than just patching on new features. We've been doing exactly that across our dev toolkit ([Scaffold-ETH 2](https://github.com/scaffold-eth/scaffold-eth-2)) and our Solidity curriculum ([Speedrun Ethereum](https://speedrunethereum.com)). The Sand Garden, an intentional team within BuidlGuidl, is executing this vision.
14+
15+
Here is a look at how we're restructuring our own Web3 stack for this shift.
16+
17+
## Structuring Docs for Agents
18+
19+
We removed Cursor rules from Scaffold-ETH 2 and replaced them with `AGENTS.md`.
20+
21+
Cursor rules only work in Cursor. `AGENTS.md` is picked up by Claude Code, Cursor, Windsurf, and any other agent harness. **One file, every tool.** Every conversation starts with the full stack context already loaded.
22+
23+
In these new workflows, we're noticing the main consumer of our docs is often an agent loading context before writing code. So we shipped `llms-full.txt`: the entire SE-2 documentation as a single flat file. Not a website. A file an agent loads into context and reasons against.
24+
25+
It's the exact same information, just formatted for how an AI actually consumes it.
26+
27+
## Swapping Complex Code for AI Skills
28+
29+
Adding a Scaffold-ETH extension used to mean resolving `package.json` conflicts through hundreds of lines of template processing code.
30+
31+
We replaced it with `/add-extension`: a simple agent skill built to work across different harnesses. Node.js handles the deterministic operations (fetching, copying), while the AI handles the judgment calls (merging). **Hundreds of lines of template code became a markdown file and a focused script.**
32+
33+
Same pattern for developer workflow. Our `pr-create` skill is a markdown file that tells an agent how to inspect the diff, format the PR body, and open it via `gh`. No custom script. No alias. Just context.
34+
35+
We've started stripping out custom scripts wherever we find that a model just naturally handles the task better.
36+
37+
## Rethinking How We Teach
38+
39+
Speedrun Ethereum is how many developers learn to build on Ethereum. We're rebuilding the learning layer to the same standard.
40+
41+
**Per-challenge context files.** Each challenge gets an `AGENTS.md` detailing the challenge overview, smart contract structure, and frontend architecture. When a learner opens a challenge in their IDE, the agent already knows the environment.
42+
43+
**AI Teacher Mode.** Type `/start` in the directory and an agent walks you through it. It asks questions, checks your understanding, guides you without giving the answer away, and reviews your code at your pace.
44+
45+
Build ideas are also migrating. Old format: a GitHub repo link. New format: a prompt you paste into your agent. The agent reads context and starts building with you.
46+
47+
## The Research Layer
48+
49+
The agent ecosystem shifts weekly. That's why we aren't assembling heavy wrappers. We need to understand the raw primitives so we can adapt the moment a new paradigm drops.
50+
51+
[raked](https://github.com/BuidlGuidl/raked) is a minimal TypeScript agent built for exactly this: the agent loop, sessions, memory, tools, skills. It's under 100 lines for the core. Built to be read, understood, and extended to solve your specific use cases.
52+
53+
Alongside it: an experimental RAG pipeline on Arbitrum DAO governance data. Vector search via `pgvector`, retrieval via LlamaIndex, automated evaluation scoring Faithfulness, Relevancy, and Correctness.
54+
55+
We built both because we really wanted to understand the underlying mechanisms before building heavier tools on top of them.
56+
57+
## Figuring Out the Boundaries
58+
59+
Security stays deterministic. Wallet interactions, transaction signing, and key management require hard boundaries. An agent making onchain transactions autonomously is an attack surface. That problem isn't solved yet.
60+
61+
But **code review** is a perfect fit for AI judgment.
62+
63+
Take [Grumpy Carlos](https://github.com/technophile-04/grumpy-carlos-personality-fetcher): a Claude Code subagent with a review personality inferred from scraped BuidlGuidl PR history. Drop it in `.claude/agents/`, ask for a review, and it responds exactly the way Carlos would: specific, strict, no vague feedback.
64+
65+
The right context, structured for an AI to use, produces better output than general AI applied to problems without context.
66+
67+
## The Compounding Effect
68+
69+
To us, this is what going "AI-first" actually looks like in practice. It's not just dropping a Copilot plugin into Scaffold-ETH. It's a stack where every layer—the framework, the docs, the extensions, the curriculum—is structured to be used by an agent, not just tolerated by one.
70+
71+
An agent building with SE-2 understands the stack. An agent teaching on Speedrun Ethereum understands the challenge. With `/add-extension` the agent can install new capabilities without leaving the conversation.
72+
73+
**Next up:** an open-source plugin that packages all of this into one installable toolkit for Claude Code, OpenCode, and Cursor.
74+
75+
## Try It Today
76+
77+
The PRs are open and the code is live. If you're building at the intersection of AI and Ethereum:
78+
79+
- **Start with raked:** [Read the agent loop.](https://github.com/BuidlGuidl/raked) Understand what a tool call actually is before building on top of abstractions.
80+
- **Look at Scaffold-ETH 2:** [See the AGENTS.md and /add-extension skills in progress.](https://github.com/scaffold-eth/scaffold-eth-2) Build your first Dapp with it and your favourite agent.
81+
- **Try the AI challenges:** Available on [Speedrun Ethereum](https://speedrunethereum.com) as they ship.

packages/nextjs/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
"@uniswap/sdk": "^3.0.3",
2222
"daisyui": "^2.31.0",
2323
"ethers": "^5.0.0",
24+
"gray-matter": "^4.0.3",
2425
"luxon": "^3.3.0",
2526
"next": "^13.4.1",
27+
"next-mdx-remote": "^6.0.0",
2628
"nextjs-progressbar": "^0.0.16",
2729
"react": "^18.2.0",
2830
"react-blockies": "^1.4.1",
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import Head from "next/head";
2+
import type { GetStaticPaths, GetStaticProps, NextPage } from "next";
3+
import { MDXRemote, MDXRemoteSerializeResult } from "next-mdx-remote";
4+
import { serialize } from "next-mdx-remote/serialize";
5+
import { BlogMeta, getAllBlogSlugs, getBlogBySlug } from "~~/services/blog";
6+
7+
const codeCls = "bg-white/5 text-primary-content px-1 py-0.5 rounded text-[0.85em] font-mono";
8+
9+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
10+
const components: Record<string, any> = {
11+
h2: ({ children }: { children?: React.ReactNode }) => (
12+
<h2 className="text-secondary font-bold text-lg sm:text-xl mt-10 mb-1">{children}</h2>
13+
),
14+
a: ({ href, children }: { href?: string; children?: React.ReactNode }) => {
15+
const isExternal = href?.startsWith("http");
16+
return (
17+
<a
18+
href={href}
19+
className="link link-primary"
20+
{...(isExternal ? { target: "_blank", rel: "noopener noreferrer" } : {})}
21+
>
22+
{children}
23+
</a>
24+
);
25+
},
26+
code: ({ children }: { children?: React.ReactNode }) => <code className={codeCls}>{children}</code>,
27+
strong: ({ children }: { children?: React.ReactNode }) => (
28+
<strong className="text-white font-semibold">{children}</strong>
29+
),
30+
ul: ({ children }: { children?: React.ReactNode }) => <ul className="mt-4 space-y-3 list-none">{children}</ul>,
31+
li: ({ children }: { children?: React.ReactNode }) => (
32+
<li className="flex items-start gap-3">
33+
<span className="text-primary-content/40 font-mono shrink-0 mt-0.5"></span>
34+
<span>{children}</span>
35+
</li>
36+
),
37+
};
38+
39+
interface Props {
40+
source: MDXRemoteSerializeResult;
41+
meta: BlogMeta;
42+
}
43+
44+
const BlogPost: NextPage<Props> = ({ source, meta }) => {
45+
return (
46+
<>
47+
<Head>
48+
<title>{meta.title} — Sand Garden</title>
49+
<meta name="description" content={meta.description} />
50+
</Head>
51+
52+
<article className="max-w-2xl px-4 py-12 mx-auto">
53+
{/* Header */}
54+
<header className="mb-10">
55+
<div className="flex items-center gap-3 mb-4 font-mono text-sm text-white/35">
56+
<span>{meta.date}</span>
57+
</div>
58+
<h1 className="text-3xl sm:text-4xl font-bold leading-tight text-white">{meta.title}</h1>
59+
</header>
60+
61+
{/* Body */}
62+
<div className="space-y-5 text-white/70 leading-relaxed text-sm sm:text-base">
63+
<MDXRemote {...source} components={components} />
64+
</div>
65+
66+
{/* Footer */}
67+
<div className="mt-16 pt-6 border-t border-white/10 font-mono text-sm text-white/35">
68+
<p>
69+
Questions or want to build together?{" "}
70+
<a href="mailto:sandgarden@buidlguidl.com" className="link link-primary">
71+
sandgarden@buidlguidl.com
72+
</a>
73+
</p>
74+
</div>
75+
</article>
76+
</>
77+
);
78+
};
79+
80+
export const getStaticPaths: GetStaticPaths = async () => {
81+
const slugs = getAllBlogSlugs();
82+
return {
83+
paths: slugs.map(slug => ({ params: { slug } })),
84+
fallback: false,
85+
};
86+
};
87+
88+
export const getStaticProps: GetStaticProps<Props> = async ({ params }) => {
89+
const slug = params?.slug as string;
90+
const { meta, content } = getBlogBySlug(slug);
91+
const source = await serialize(content);
92+
return { props: { source, meta } };
93+
};
94+
95+
export default BlogPost;

0 commit comments

Comments
 (0)