diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e8a01bb..d30f257 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -22,15 +22,29 @@ jobs:
         with:
           name: macform-darwin-arm64
           path: bin/macform
+      - name: Build integration test binary
+        run: GOOS=darwin GOARCH=arm64 go test -c -tags=integration -o integration.test ./integration/
+      - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1
+        with:
+          name: integration-test
+          path: integration.test
 
   integration:
     needs: build
-    runs-on: getmac
+    runs-on: getmac-tahoe
     steps:
+      - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 #v6.0.3
       - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 #v7.0.0
         with:
           name: macform-darwin-arm64
-      - name: Make executable
-        run: chmod +x macform
-      - name: Smoke test
-        run: ./macform --version
+      - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 #v7.0.0
+        with:
+          name: integration-test
+          path: integration
+      - name: Make executables
+        run: chmod +x macform integration/integration.test
+      - name: Integration tests
+        working-directory: integration
+        run: ./integration.test -test.v
+        env:
+          MACFORM: ${{ github.workspace }}/macform
diff --git a/go.mod b/go.mod
index 51d9520..da8cb86 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/vsimon/macform
 go 1.25.0
 
 require (
+	github.com/rogpeppe/go-internal v1.15.0
 	github.com/spf13/cobra v1.10.2
 	gopkg.in/yaml.v3 v3.0.1
 )
@@ -10,4 +11,6 @@ require (
 require (
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 	github.com/spf13/pflag v1.0.9 // indirect
+	golang.org/x/sys v0.26.0 // indirect
+	golang.org/x/tools v0.26.0 // indirect
 )
diff --git a/go.sum b/go.sum
index 47edb24..c1973bb 100644
--- a/go.sum
+++ b/go.sum
@@ -1,12 +1,18 @@
 github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/rogpeppe/go-internal v1.15.0 h1:D0RCU5rMAp+SpgkiNdrjfJ+LX4J1M32V2NeCY7EJ6hc=
+github.com/rogpeppe/go-internal v1.15.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
 github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
 github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
 github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
+golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
+golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
+golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/integration/integration_test.go b/integration/integration_test.go
new file mode 100644
index 0000000..5990b7e
--- /dev/null
+++ b/integration/integration_test.go
@@ -0,0 +1,30 @@
+//go:build integration
+
+package integration
+
+import (
+	"os"
+	"testing"
+
+	"github.com/rogpeppe/go-internal/testscript"
+)
+
+var macformBin string
+
+func TestMain(m *testing.M) {
+	macformBin = os.Getenv("MACFORM")
+	if macformBin == "" {
+		panic("MACFORM env var not set — pass the path to the macform binary")
+	}
+	os.Exit(m.Run())
+}
+
+func TestScripts(t *testing.T) {
+	testscript.Run(t, testscript.Params{
+		Dir: "testdata",
+		Setup: func(env *testscript.Env) error {
+			env.Setenv("MACFORM", macformBin)
+			return nil
+		},
+	})
+}
diff --git a/integration/testdata/version.txtar b/integration/testdata/version.txtar
new file mode 100644
index 0000000..44cc32e
--- /dev/null
+++ b/integration/testdata/version.txtar
@@ -0,0 +1,2 @@
+exec $MACFORM --version
+stdout 'macform dev'
diff --git a/mise.toml b/mise.toml
index c3b0d06..6e8b760 100644
--- a/mise.toml
+++ b/mise.toml
@@ -22,6 +22,11 @@ run = "go build -o bin/macform main.go"
 description = "Run tests"
 run = "go test ./..."
 
+[tasks.integration-test]
+description = "Run integration tests"
+depends = ["build"]
+run = "MACFORM=$PWD/bin/macform go test -tags=integration -v -count=1 ./integration/..."
+
 [tasks.clean]
 description = "Remove build artifacts"
 run = "rm -rf bin/"
