Teaching the Agent Our Craft: Structured Agentic Development on a Real Codebase授 AI 以技:在真实代码库中构建结构化智能体

Teaching the Agent Our Craft: Structured Agentic Development on a Real Codebase

Our small dev team went from a blank slate to a platform helping patients overcome chronic pain且看我方小队,如何从零起步,铸就一套助人摆脱慢性疼痛的数字平台

Alex Haldeman

July 06, 2026 2026 年 7 月 6 日

The Mission使命

We recently partnered with a startup that had developed a clinically proven approach to alleviating neuroplastic chronic pain. Their program worked: a coach-led model that helped patients ease chronic pain at a lower cost than conventional treatment. The problem was reach. The in-person model could not scale to the demand they were seeing, and there were not enough coaches to close the gap. We were brought in to build a digital platform that could deliver the program to every patient who needed it.近期,我方与一家初创公司结盟。彼等研发出一套临床验证有效的方法,专治神经可塑性慢性疼痛。其模式以教练为核心,较之传统疗法,既省钱又见效。然则,此法受限于人手,难以规模化推广,教练缺口甚大。我方受托构建数字平台,旨在将此良方惠及每一位病患。

Our Development Philosophy and Inspiration开发之道与灵感之源

At 8th Light, we approach agentic development the same way we approach any software engagement: with discipline around test-driven development, clean architecture, and code that is built to embrace change. But agentic development comes with its own failure modes. An agent produces code that covers the happy path and misses critical behaviors. A context window fills with stale reasoning from earlier attempts, and the agent starts working against itself. Without explicit conventions, the output works but looks like nobody on the team wrote it.在 8th Light,我们对待智能体开发,一如对待寻常软件工程,讲究测试驱动开发(TDD)、架构清晰,代码须得从容应对变局。然智能体自有其短板:它写出的代码,往往只顾顺境,却漏了关键逻辑;上下文窗口若塞满陈旧推理,它便会自乱阵脚。若无明确规矩约束,产出的代码虽能运行,却似无主之物,毫无章法。

Tyler Burleigh's Research-Plan-Implement gave us a useful frame for thinking about this. His core observation: the bottleneck is not code generation, it is ensuring the model understands what to build before it starts building. RPI addresses that by separating research, planning, and implementation into distinct phases, each with a review cycle before the next begins. We adapted that structure into our Claude Code workflow, with the additional goal of keeping product managers and designers genuinely in the loop at each transition, not just developers.Tyler Burleigh 提出的“研究-规划-实现”(Research-Plan-Implement)框架,令我们茅塞顿开。其核心见解在于:瓶颈不在于代码生成,而在于模型动笔前是否真懂需求。RPI 将三者拆分,层层评审,步步为营。我们将此结构引入 Claude Code 工作流,并力求让产品经理与设计师全程参与,而非仅由开发者孤军奋战。

What follows is a description of the harness we built from a Claude Code-specific perspective.下文便将从 Claude Code 的视角,细说我们所筑的这套“护具”。

The Harness护具之构

Structure架构

Before walking through the pieces, it helps to see how they fit together. Everything that teaches the agent our craft lives in a handful of files at the project root and inside a single .claude/ directory. None of it is application code. It is the scaffolding that sits alongside the code and shapes how the agent works within it.在拆解细节前,先观其全貌。凡是教导智能体掌握我方技艺的规矩,皆藏于项目根目录及 .claude/ 文件夹中。这些皆非业务代码,而是辅佐代码运行的“脚手架”,用以规训智能体的行事方圆。

The map below ignores the application source entirely and shows only that scaffolding. Each branch is a separate part of the framework, and the sections that follow zoom into them one at a time.下方的拓扑图略去业务源码,专显这套脚手架。每一分支皆为框架之要义,后文将逐一剖析。

pain-management-app/
├── CLAUDE.md            # the knowledge root: project context, critical rules, naming conventions, architecture
├── .mcp.json            # connections to the outside: Linear (product), Figma (design), internal services
└── .claude/
    ├── rules/           # path-scoped rules that codify how we write code, auto-loaded by file path
    ├── skills/          # the workflow: story-writer → tdd-build → pr-summary → code-review
    ├── agents/          # a test-writer subagent that writes tests with no view of the implementation
    ├── hooks/           # guardrails that enforce the boundaries (e.g. the test-writer touches only test files)
    └── commands/        # small routine helpers for linting, type-checking, and installs

 

The root of our knowledge知识之根

Everything starts from a single file. CLAUDE.md is the one place the agent has to find on its own, and it carries the project context that applies everywhere: what we are building, the principles we hold to, the conventions and critical rules that span the whole codebase, and the pointers to everything else the agent should load. From there it reaches the path-scoped rules and the rest of the framework.万事皆由一文件始:CLAUDE.md。这是智能体必寻之所,内含项目全局心法:目标为何、准则几何、代码规范,以及它需加载的一切索引。由此出发,它方能触及各路径下的特定规矩。

The critical rules that live here are short and unambiguous, the kind of thing that is obvious to the team and invisible to a fresh model. They tend to encode the habits you would otherwise repeat in code review:此处的关键规则短促而明晰,乃团队心照不宣之琐事,却常为新进模型所忽略。它们多是些你在代码评审中反复叮嘱的习惯:

1. Don't write speculative code. Every function, endpoint, or field
   must be used by something in the same change.
2. Tests come before implementation, and assert behavior, not internals.
3. Reuse an existing component or utility before introducing a new one.
4. Comments explain WHY, not WHAT.

Getting this root right matters more than any single rule beneath it, because every other part of the framework is reached through it.根基若正,万事皆顺。此处的规矩,重于下方任何细则,盖因框架万变,皆由此出。

 

Codifying our approach in a context-aware way将技艺融入上下文

The conventions a senior developer carries in their head, such as how to structure a query, which test selector to reach for first, or where business logic belongs, don't come from a single global rule. They depend on where you are in the codebase. The same is true for the agent. Loading everything the agent might ever need into one file would work, but it wastes context and buries the relevant guidance under rules that don't apply to the task at hand.资深开发者胸中自有丘壑,如查询如何构造、测试选择器如何取舍、业务逻辑归于何处,皆非一纸条文所能尽述,而取决于所处代码位置。智能体亦然。若将所有规矩尽数塞入一处,虽可行,却徒耗上下文,且令关键指引淹没于冗余中。

Claude Code's path-scoped rules solve this directly. Each rules file declares the paths it governs in its frontmatter, and Claude loads it automatically when the agent works with matching files. The anatomy is simple:Claude Code 的路径规则(path-scoped rules)恰好解此难题。每个规则文件在元数据中声明其管辖范围,智能体处理相关文件时,便自动加载。其理甚简:

---
paths:
  - "frontend/src/**/__tests__/**/*"
  - "frontend/src/**/*.test.*"
---

# Frontend Testing
... rules for testing go here

A rules file targeting backend source files never loads during a frontend task. That keeps context lean and, more importantly, keeps the guidance specific. The agent working on a backend service sees the Router → Service → Repository architecture rules. The agent writing a frontend test sees the testing conventions. Neither has to wade through the other's rules.后端规则,前端不载。如此,上下文轻盈,指引精准。处理后端服务时,它只见“路由-服务-仓库”架构之法;处理前端测试时,它只见测试规范。互不干扰,清净自在。

That specificity is what made the rules files pay off on this project. One example: our frontend testing rule makes explicit when to reach for each Testing Library selector.正是这份精准,让规则文件在此项目中大放异彩。举例言之,前端测试规则明确了何时该用 Testing Library 的哪种选择器。

- `getBy*`: Element is already in DOM (sync, throws if missing).
- `findBy*`: Wait for element to appear (async, throws if missing). Use instead of `waitFor` + `getBy`.
- `queryBy*`: Assert element is NOT present (sync, returns null).

This is the kind of guidance a developer picks up after a few code reviews. Without it, an agent reaching for waitFor + getBy when findBy is the right tool will produce tests that work but don't match how the team writes them. With it, the first draft is already consistent. The same held for our backend architecture rules, our API layer conventions, and our state management patterns. The rules files turned each of those into things the agent just knew. More importantly, when we noticed the agent diverging from our conventions, or spotted a better approach ourselves, we had a feedback loop for folding that lesson back in.此等指引,原是开发者经数次评审方能领悟。若无此规,智能体误用 waitFor + getBy,虽能跑通,却非团队正道。有了规矩,初稿即合规范。后端架构、API 层约定、状态管理模式,皆是如此。规矩文件令智能体“无师自通”。更妙的是,一旦发现它偏离正道,或有更佳方案,我们即刻修正规矩,形成闭环。

The backend rules carry the same kind of specificity. The architecture rule does not just say "use Router → Service → Repository", it shows the dependency wiring the agent is expected to produce, down to creating the repository inside the DI function:后端规则亦如是。架构规矩不仅言明“用 Router → Service → Repository”,更展示了依赖注入的接线法,细致到如何在 DI 函数中创建仓库:

async def get_playlist_service(
    session: Annotated[AsyncSession, Depends(get_session)],
    catalog_client: Annotated[CatalogClient, Depends(get_catalog_client)],
) -> PlaylistService:
    repository = PlaylistRepository(session)
    return PlaylistService(repository, catalog_client)

PlaylistServiceDep = Annotated[PlaylistService, Depends(get_playlist_service)]

With that in front of it, the agent writes a new service the way the team writes the rest: HTTP concerns in the router, business logic in the service, SQL confined to the repository.有此在前,智能体写出的新服务,便与团队旧作如出一辙:HTTP 归路由,逻辑归服务,SQL 锁仓库。

 

Creating collaboration through integration借集成以促协作

Engineering knowledge was now codified, but product and design still lived in separate tools the agent could not see. We needed a way to bring them into the same workflow. We used Linear for backlog management and roadmap planning, and Figma for our design system and UI flows. Model Context Protocol (MCP) is an open standard that gives AI agents a uniform way to connect to external tools and services. Rather than copying context from a Linear ticket or a Figma file into a prompt, the agent reads from and acts on those tools directly, the same way a developer tabs between their editor and a browser.工程知识虽已编码,然产品与设计仍存异处。我们引入 Linear 管理进度,Figma 沉淀设计。利用模型上下文协议(MCP),智能体得以直接读写这些工具,如同开发者在编辑器与浏览器间切换,无需再在提示词中搬运上下文。

To share these connections across the team, we committed an .mcp.json file to the repository. Any developer who clones the repo picks up the full set of integrations immediately. The file also handles connections that require more care, whether that is a custom setup script for local tooling or an API token that cannot be committed to source control:为使团队共享此连接,我们将 .mcp.json 提交至库中。任何开发者克隆项目,即刻拥有全套集成。此文件亦处理敏感连接,如本地工具脚本或 API 令牌,避开源码泄露之忧:

{
  "mcpServers": {
    "linear": {
      "type": "http",
      "url": "https://mcp.linear.app/mcp"
    },
    "figma": {
      "type": "http",
      "url": "https://mcp.figma.com/mcp"
    },
    "ehr-service": {
      "command": "node",
      "args": [
        "${EHR_SETUP_PATH}"
      ]
    },
    "cms-service": {
      "type": "http",
      "url": "https://mcp.fake-cms-service.io",
      "headers": {
        "Authorization": "Bearer ${FAKE_CMS_MCP_TOKEN}"
      }
    },
    "some-docs-server": {
      "type": "http",
      "url": "https://some-docs-server.com/api/mcp"
    }
  }
}

MCP servers are not limited to collaboration tools. We connected our EHR and CMS services the same way, which made a noticeable difference in code quality and troubleshooting. One example stands out: a developer connected the Figma MCP, pulled the design system directly into the agent's context, and built a 1-to-1 match using a custom design tokens page backed by real application components. Whenever the design and the code drifted, re-syncing was a single command rather than a manual audit.MCP 服务器不限于协作工具。我们连通了 EHR 与 CMS 服务,代码质量与排错效率大增。有一例尤为亮眼:开发者连通 Figma MCP,将设计系统直接纳入上下文,构建出与设计稿分毫不差的页面。设计与代码若有出入,只需一令重同步,无需人工比对。

 

Building our workflow构建工作流

Codified knowledge and connected tools still left one thing open: structure for the work itself. We built two skills that map directly onto RPI's phases: /story-writer handles research and planning, /tdd-build handles implementation.知识已定,工具已连,唯余工作流之骨架。我们筑起两项技能,对应 RPI 之阶段:/story-writer 主攻研究与规划,/tdd-build 主攻实现。

/story-writer/story-writer

The skill starts at Linear. Give it a ticket ID and it reads the existing description. Give it nothing and it creates a new ticket and works from there. Either way, it then explores the codebase before drafting anything, not because it needs to write code, but so the implementation steps it produces are grounded in the project's actual structure. A step that references the right domain folder or calls out a real constraint is more useful than a generic checklist.此技始于 Linear。给它工单 ID,它便读其详述;若无,它自创工单。它先探查代码库,非为写码,而是确保实现步骤立足于项目实情。引用真实领域目录或约束的步骤,远胜泛泛之谈。

What makes it feel collaborative rather than generative is the interview loop. The agent asks clarifying questions in conversation until the requirements are specific enough to write acceptance criteria against. Once both parties are satisfied, it writes the story in a structured format: an overview, implementation steps pitched at what to build, not how, and acceptance criteria that can be verified in the app. The approved story goes back to Linear and becomes the shared source of truth for the whole team.其精妙在于“访谈闭环”。智能体不断追问,直至需求明晰,方定下验收标准。双方点头,它便撰写结构化故事:概览、实现步骤、验收标准。获批后,此故事回填 Linear,成为全队共识。

The structured format is fixed, which is what makes the output reviewable instead of a wall of prose:结构固定,产出便可评审,而非一堆废话:

Overview
- Purpose and scope of the story, in a few sentences

Implementation Steps
- Meaningful units of work grouped by concern (Backend, Frontend, Testing),
  pitched at what to build, not a file-by-file how

Acceptance Criteria
- Checks someone can actually perform in the running app

One habit we developed: including the Figma MCP link for the relevant design file directly in the story description. When /tdd-build reads the ticket to start implementation, it can pull the design into its context through the same MCP connection and work with the actual component designs rather than a written description of them.我们养成一习惯:将 Figma MCP 链接附于工单。当 /tdd-build 启动时,它能直接拉取设计稿,依图施工,而非仅凭文字描述。

/tdd-build/tdd-build

The skill reads the Linear ticket, explores the relevant parts of the codebase, then enters plan mode and proposes the implementation as a numbered list of TDD cycles. Each cycle specifies a test file, a behavioral spec, the exact command to run, and a RED gate reason: why the test should fail before any implementation exists.此技读工单、探库,而后入规划模式,列出 TDD 周期清单。每周期含测试文件、行为规格、运行指令及“红灯理由”:即为何此测试在实现前必败。

Cycle 1: GET /playlist/{id} returns playlist with tracks
- Test file: backend/tests/playlists/test_playlist_router.py
- Test spec: GET /playlist/{id} returns 200 with {id, name, tracks[{id, name}]}
- Test command: cd backend && python -m pytest tests/playlists/test_playlist_router.py -v
- RED gate: endpoint does not exist
- Implementation: add GET /playlist/{id} router, service, and repository
- Files: backend/src/playlists/router.py (new), service.py (new), repository.py (new)

Nothing gets written until the developer has reviewed and approved the plan.开发者不点头,它便不动笔。

Once approved, the build begins. For each cycle, the main agent dispatches the test-writer subagent with the behavioral spec as its only context. The subagent starts from a fresh context window and has no knowledge of the implementation the main agent is about to write. That separation is deliberate. A test written with the implementation already in view tends to describe that implementation, not the behavior we actually care about. Working from a behavioral spec keeps the test focused on what the system should do. The subagent runs the tests, confirms they fail for the right reason, and returns a RED gate report. Only then does the main agent write the minimum code to make them pass.获批后,构建始。主智能体派发测试子智能体,仅给行为规格。子智能体上下文清零,不知实现细节。此乃刻意为之,防其见实现而写测试,导致测试沦为实现的附庸。如此,测试方能专注系统之本。子智能体跑测试,确认失败,呈报红灯报告。主智能体方才动手,以最简代码令其通过。

The fresh context also means the subagent cannot drift toward the implementation. With nothing to glimpse, it has no shortcut to rationalize and no way to shape its tests around how the code happens to be structured.上下文清零,亦令子智能体无法投机取巧,无法依循代码结构去凑测试。

The subagent is configured by a declarative definition that sets how it behaves and what it can access. Its frontmatter names the only tools it can reach for and registers the hook that will police them:子智能体由声明式定义配置,规定其行为与权限。其元数据列出唯一可用工具,并注册监管钩子:

---
name: test-writer
description: Writes failing tests for a single TDD cycle, isolated from any implementation.
tools: Read, Glob, Grep, Write, Edit, Bash
hooks:
  PreToolUse:
    - matcher: "Edit|Write"
      hooks:
        - type: command
          command: "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/restrict_test_writer_paths.py\""
---

Listing the hook in frontmatter is what wires it in, but the enforcement lives in the script itself. Even with a prompt that explicitly forbids touching implementation files, a sufficiently confused agent might try, so restrict_test_writer_paths.py is the hard backstop. It fires on every Edit and Write the subagent makes and checks the target path against an allowlist:钩子挂于元数据,然强制力在脚本。即便提示词严禁触碰业务文件,智能体若糊涂,仍可能越界。故 restrict_test_writer_paths.py 乃最后防线。它监控每次编辑,若路径不在白名单,便行阻断:

ALLOWED_PATTERNS = (
    re.compile(r"(?:^|/)backend/tests/"),
    re.compile(r"(?:^|/)__tests__/"),
    re.compile(r"\.test\.[^/]+$"),
    re.compile(r"(?:^|/)frontend/src/testing/"),
)

The matching runs only for the test-writer, so every other agent (including the main conversation) passes through untouched. When a path fails the check, the script hands Claude Code a structured decision before the file is ever touched:此匹配仅对测试编写者生效。若路径违规,脚本在文件被触碰前,即向 Claude Code 呈报结构化决策:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "test-writer may only write test files. Refusing to modify <path>."
  }
}

The reason comes back to the agent so it can report clearly rather than retry. The prompt states the intent, and the hook is what actually enforces it.理由回传,智能体便能明晰缘由,而非盲目重试。提示词定意图,钩子行法度。

 

The results成果

The clearest outcome was how much a small team could carry. A pair of developers took on a scope that would normally demand more hands: a multi-tenant platform, an AI coaching companion bounded by real safety constraints, and a data architecture built to keep sensitive information out of reach. The harness was what made that possible. It let two people move through that scope quickly without the work looking like two people rushing, because the conventions, the architecture rules, and the test-first cycle were already encoded for the agent to follow.最显著者,乃小队之负荷大增。两人之力,竟成多租户平台、AI 教练及安全数据架构。全赖这套“护具”,两人行进如飞,却无忙乱之态,盖因规矩、架构与测试先行之法,皆已嵌入智能体之魂。

Speed was not the only thing we watched. Scope stayed under control as the work went on, rather than being quietly dropped to keep up the appearance of speed. That is usually what separates genuine progress from debt you only discover later. The same structure that kept the agent honest, research before planning and a failing test before any implementation, is what kept the codebase coherent under pressure.我们不仅求速,更求稳。进度未因求快而牺牲,此乃真进步与技术债之分野。研究先行、测试先行,此结构既束缚智能体,亦在压力下保全了代码库之纯粹。

The integration paid off just as much away from the keyboard. Wiring Linear and Figma into the agent's workflow through MCP collapsed the lag between a design decision, a product priority, and the code that implemented it. Re-syncing a built component against an updated design became a single command instead of a manual audit, and the feedback loop between engineering and the rest of the team got tighter in a way that had previously been tedious.集成之利,亦在键盘之外。通过 MCP 将 Linear 与 Figma 纳入工作流,消弭了设计决策与代码实现间的鸿沟。组件重同步,一令即达,往日繁琐,今朝弹指间。

This approach was an accelerant to our team's abilities, not a replacement. The harness did not execute everything on its own. Engineers still stepped in to scaffold code when a cleaner structure was needed, or to adjust how a test was written, and then folded that lesson back into the rules so the agent carried it forward. That loop, where engineers kept improving the harness and the harness let them cover more ground, is what made the approach worth keeping. What started as experimentation on one engagement is now a repeatable practice we can bring to other work.此法乃团队之助推,非替代。智能体非万能,工程师仍需在关键处架构、调优测试,再将心得反哺规矩。此循环——工程师完善护具,护具助工程师拓土——正是此道之价值所在。始于实验,今已为我们之必修课。

 

How to get started如何起步

Sometimes, the biggest challenge to making innovation "stick" is the drag of organizational momentum. Have an idea, workflow, or challenge that has been a blocker for your business? Let's talk.创新之难,常在于组织惯性。若君有志,或有阻滞,何不共话?

Spark a conversation >开启对话 >

Alex HaldemanAlex Haldeman

Lead Engineer首席工程师

Alex is a full-stack engineer and consultant with over a decade of experience building software across healthcare, finance, government, and defense. His work spans backend systems, frontend applications, and cloud infrastructure, giving him a broad view of how the pieces of a product fit together and where the hard problems tend to surface. In recent engagements he has focused on AI-powered systems and agentic development, exploring how these tools change the way software gets designed, built, and shipped. He works in a test-driven, agile style and places equal value on engineering fundamentals and the newer practices reshaping the field. Across his engagements he has taken projects from early architecture through delivery, often serving as the technical lead on cross-functional teams, and he regularly mentors the engineers he works alongside. He's interested in writing about the craft of building software and what he is learning as the tools and the work continue to evolve.Alex 乃全栈工程师,深耕医疗、金融、政府与防务软件十余载。其涉猎后端、前端与云基础设施,洞悉产品之机理与难点。近期专攻 AI 与智能体开发,探究其如何重塑软件之设计与交付。他崇尚测试驱动与敏捷之道,深信工程基础与新兴实践同等重要。从架构起步至交付,他常任跨职能团队之技术领路人,且乐于提携后进。他热衷于记录软件构建之技艺,并随工具演进而不断求索。