从头开始用 Swift 构建一个编码代理
Building a coding agent in Swift from scratch

原始链接: https://github.com/ivan-magda/swift-claude-code

该项目通过用Swift重建Claude Code等高效编码代理的核心功能,来探索其背后的架构。作者假设,**简单性和紧凑的循环设计,利用强大的LLM,比复杂的编排更重要。** 该系列文章在ivanmagda.dev上详细介绍,逐步构建一个CLI代理,专注于极简方法:核心循环和一组高质量的工具(搜索、文件编辑)。关键测试原则包括优先考虑模型推理而非大量的脚手架,明确的任务状态,以及受控的上下文注入而非持久内存。 该项目分阶段进行,从核心机制(代理循环、工具分发)开始,逐步推进到产品特性,如子代理、技能加载和上下文压缩。它使用Swift 6.2和AsyncHTTPClient构建,并在GitHub上可用,有意保持为一个集中的探索,而不是一个完整的Claude Code克隆。目标是确定一个功能性编码代理的*最小*可行架构。

## Swift 编码代理项目总结 一位开发者 (vanyaland) 使用 Swift 从头开始构建了一个编码代理,并在 GitHub 上分享了该项目 ([github.com/ivan-magda](https://github.com/ivan-magda))。该项目旨在证明有效的代理行为并不需要复杂的框架,而是侧重于围绕强大的语言模型构建一个“薄包装器”。 讨论重点是长期运行的代理会话中的**上下文管理**挑战,以及诸如总结过去交互以避免性能下降的解决方案。Swift 语言因其**结构化并发**和**强类型系统**而受到赞扬,这简化了工具模式的定义。 一些评论者也在构建类似的代理,其中一些使用 Python,并分享了关于工具和架构的见解。人们对集成未来的 Apple Intelligence 功能感兴趣,尽管当前的 Gemini 集成是基于云的。该项目引发了关于模型能力与代理编排层重要性之间平衡的讨论。开发者已经解决了命名问题,将 CLI 组件重命名以避免与 Anthropic 的 "Claude" 产生潜在的法律问题。
相关文章

原文

Exploring the architecture of coding agents by rebuilding a Claude Code-style CLI from scratch in Swift.

demo

A complete 9-part learning series is available on ivanmagda.dev.

Start the series →

Claude Code feels unusually effective compared to other coding agents, and I suspect most of it comes from architectural restraint rather than architectural complexity. I studied the tool surface, traced the interaction loop, and tried to isolate which design choices actually matter.

My working theory: coding agents benefit more from a small set of excellent tools and tight loop design than from large orchestration layers.

Claude Code doesn't have many tools. The tools it does have are simple: a search tool, a file editing tool. But those tools are really good. And the system leans on the model far more than most agent implementations — less scaffolding, more trust in the LLM to do the heavy lifting.

This project tests that idea by rebuilding the core mechanics from scratch in Swift, one stage at a time, to see how little architecture you actually need.

This project tests a few specific ideas about coding agents:

  • A small number of high-quality tools beats a large tool catalog
  • The model should do most of the heavy lifting — thin orchestration, not thick
  • Explicit task state improves reliability more than prompt-only planning
  • Controlled context injection matters more than persistent memory
  • Context compaction is a product feature, not just a token optimization

Each stage is designed to isolate one mechanism and see what it enables.

The whole thing boils down to one loop:

func run(query: String) async throws -> String {
    messages.append(.user(query))

    while true {
        let request = APIRequest(
            model: model, system: systemPrompt, messages: messages, tools: Self.toolDefinitions
        )
        let response = try await apiClient.createMessage(request)
        messages.append(Message(role: .assistant, content: response.content))

        guard response.stopReason == .toolUse else {
            return response.content.textContent
        }

        var results: [ContentBlock] = []
        for block in response.content {
            if case .toolUse(let id, let name, let input) = block {
                let output = await executeTool(name: name, input: input)
                results.append(.toolResult(toolUseId: id, content: output, isError: false))
            }
        }
        messages.append(Message(role: .user, content: results))
    }
}

The loop is the invariant. Tools are the variable. Every stage adds entries to the tool handler dictionary and injection points before the API call, but the loop body itself never changes.

Progress is tracked via git tags. The roadmap is split into two phases — core mechanics first, then product-level features.

The minimum viable agent: a loop and a small set of good tools.

Stage What It Adds Tag
00 Bootstrap: SPM project, two-target layout, CI 00-bootstrap
01 Agent loop + bash tool 01-agent-loop
02 Tool dispatch: read_file, write_file, edit_file with path safety 02-tool-dispatch
03 Todo tracking with nag reminder injection 03-todo-write

Phase 2 — Product Mechanics

The features that make an agent feel like a usable product: context, memory management, and persistence.

Stage What It Adds Tag
04 Subagents: recursive loop with fresh context 04-subagents
05 Skill loading: .md files injected as tool results 05-skill-loading
06 Context compaction: 3-layer strategy (micro, auto, manual) 06-context-compaction
07 Task system: file-based CRUD with dependency DAG 07-task-system
08 Background tasks: Task {} + actor-based notification queue 08-background-tasks

Two-target Swift Package Manager project:

Core is the library — API client, shell executor, agent loop, tools.

CLI is just the entry point. The executable is called claude.

Raw HTTP to POST https://api.anthropic.com/v1/messages using AsyncHTTPClient. Works on both macOS and Linux.

This project is not:

  • A full Claude Code clone or drop-in replacement
  • A general-purpose multi-agent framework
  • Production-ready IDE tooling

It's a staged exploration of coding-agent architecture — intentionally minimal, intentionally incomplete.

  • Swift 6.2 with strict concurrency
  • AsyncHTTPClient (SwiftNIO-based) for cross-platform HTTP + streaming SSE
  • Foundation Process for shell command execution
  • macOS 10.15+ / Linux
git clone https://github.com/ivan-magda/swift-claude-code.git
cd swift-claude-code

# Set up your API key and model
cp .env.example .env
# Edit .env with your ANTHROPIC_API_KEY and MODEL_ID

swift build
swift run claude

MIT

联系我们 contact @ memedata.com