Replacing Bash with Swift in an AI Harness

ianhxu2 pts0 comments

Replacing Bash with Swift in an AI Harness | Alejandro M. P.

Series: Build an Agent Harness

Have You Built an Agent Harness Yet?

AI doesn't remember your project, Markdown does

Do We Even Need Multiple Tools?

Sandboxing an AI Harness on macOS

Teaching Skills to an AI Harness

Replacing Bash with Swift in an AI Harness

22 May 2026<br>10min read

Replacing Bash with Swift in an AI Harness

22 May 2026

Alejandro M. P.

A few weeks ago I read An Interpreter for Swift, from Cocoanetics, and I had that nice feeling of somebody else having already articulated the thing that was vaguely floating in your head.<br>Let me just say it outright: I get very sad every time somebody insists that TypeScript is the future of agentic coding. So I kept sending my wish to the universe that Swift should be also in the race for that. Now – finally – I was able to manifest the missing piece: an interpreter for the language I love. - Cocoanetics

That resounded inside me as I’ve always thought that Swift was the ideal language for this. And if I am already building a tiny Swift AI harness to learn how these systems work, then this felt like the perfect place to test the idea. So I immediately knew I had to try using this Swift interpreter in the harness. Even if the project is still tiny and mostly for learning, I thought it could still be useful.<br>The old Bash<br>In the previous post I had already replaced the little file toolbox with bash, mostly to see what happened if I stopped pretending those file tools were anything other than wrappers around shell commands.<br>So we were already in a good position to perform the next part of the experiment and answer, what if the generic tool was not bash, but Swift?<br>Instead of letting the model write shell, let it write whatever top-level Swift it needs to accomplish the task. That sounds much nicer to me already.<br>Want the finished project?<br>The whole point of this post is that you build it yourself, and all the important ideas are already here. But if you want to support my writing, or you just want to save time, I packaged the project for you to download.<br>Get the harness by supporting me on Buy me a coffee

The first fork in the road<br>The most obvious version of the idea is very simple. Keep the harness the same. Just replace bash with a swift tool. Let the model write top-level Swift, and call out to the compiler to execute it.<br>That would definitely work, but running real Swift brings the whole toolchain with it. Module caches. Compiler behavior. We all know that running Swift means going through a compilation step, and that is not the fastest thing in the world, especially if we need to start a new compiler process every time. And given LLMs might roundtrip many times to accomplish a task, any gains we get here are worth it. It is the usual reality of “this is a language toolchain”, not “this is a tiny embedded runtime”.<br>It also means we have the security issues we had with Bash, we can still use Seatbelt of course, but maybe we can take this chance to do better.<br>And finally, I just wanted to use the Swift Interpreter. Despite not being an official solution, it looks very promising and useful, and like something that should have been taken more seriously over the years. I still think Swift is the best language even for scripting, but performance is not there. So in my head there have always been two options: increase the performance of the toolchain and be as fast as Jai, or accept the limits and make a faster interpreter. So what we have here now, despite not coming from the core team, lets us prove the second idea.<br>Embedding Swift<br>That is where SwiftScript becomes interesting.<br>SwiftScript is a tree-walking Swift interpreter that you can embed as a library. No swiftc. No shelling out to swift -e. Just parse Swift and interpret it.<br>Now the swift tool is not another subprocess. It can just be part of the harness itself. So we just make a new ToolDefinition that looks very similar to the bash one.<br>static func swift() -> Self {<br>ToolDefinition(<br>name: "swift",<br>description: "Run top-level Swift code directly inside the harness process, using SwiftScript as the execution engine and ShellKit for workspace confinement.",<br>arguments: ["code"],<br>run: { arguments, workspaceRoot in<br>let code = arguments["code"] ?? ""<br>let result = await SwiftScriptToolRunner.executeInProcess(<br>code: code,<br>at: workspaceRoot

return if result.exitCode == "ExitStatus(0)",<br>let stdout = result.stdout.nonEmpty {<br>stdout<br>} else {<br>executionResultJSON(<br>stdout: result.stdout,<br>stderr: result.stderr,<br>exitCode: result.exitCode<br>Where does the interpreter run?<br>This was the next question I had to understand. I have experience writing interpreters and things are easy when you just need to exercise pure code. Interpreting a syntax tree that wants a mathematical computation is trivial, but things get trickier when you start talking about I/O and other features that need to interact with an “environment”.<br>So we have an interpreter that we can...

swift harness bash interpreter code already

Related Articles