Long press any element of your iOS app in the simulator, say what is wrong, and the report lands in your Claude Code session
翻譯準備中
外掛JavaScript · SwiftGitHub @ostiums自行安裝營運者未確認
試用過了嗎? 點一下就好,不需要登入。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
安裝型專案無需部署網域也可驗證。個人儲存庫可透過 GitHub 登入驗證,組織儲存庫可使用上方的儲存庫驗證檔案。
正在載入完整 README。 以下為已儲存的摘錄。
Long press anything in your iOS, React Native or Flutter app in the simulator, say what's wrong, and Claude Code or Codex fixes it.
Watch the demo in full quality (MP4, 47 s)
1. Long press an element and type what's wrong.
2. The report lands in your agent session: your words, the element, a screenshot.
3. The agent fixes the code and relaunches the app. A banner tracks it: queued → fixing → rebuilding → live.檢視完整 README ↗Long press anything in your iOS, React Native or Flutter app in the simulator or the Android emulator, say what's wrong, and Claude Code or Codex fixes it.
Overview • Getting started • Platforms • How it works • Try it on Tally • Troubleshooting
Watch the demo in full quality (MP4, 47 s)
FixKit turns a long press in the iOS simulator, or in the Android emulator for React Native and Flutter apps, into a prompt for your coding agent. The report carries your words, a screenshot with the element outlined, and the code behind the element: a SwiftUI file and line, a UIKit property, a React Native component or a Flutter widget. The agent fixes the code and puts the change on screen, and a banner in the app follows the report until the fix is live.
[!TIP] To try FixKit without an app of your own, use Tally, the SwiftUI wallet in this repository with four seeded UI bugs. It takes two commands.
FixKit has two halves:
127.0.0.1:4747), turns each report into a prompt.[!NOTE] FixKit works in the iOS simulator and, for React Native and Flutter, in the Android emulator: not on a physical device.
Recommended:
FIXKIT_AXE, then on PATH (brew install cameroncooke/axe/axe), then in the copy bundled with XcodeBuildMCP run through npx. On Android the receiver reads the same through adb, with nothing more to install.Claude Code:
claude plugin marketplace add ostiums/fixkit
claude plugin install fixkit@fixkit
Codex:
codex plugin marketplace add ostiums/fixkit
codex plugin add fixkit@fixkit
Add .fixkit/ to .gitignore: reports and screenshots go there.
With Claude Code, let it read the screenshots without asking, in .claude/settings.json:
{ "permissions": { "allow": ["Read(./.fixkit/**)"] } }
In Xcode: File › Add Package Dependencies › https://github.com/ostiums/fixkit, rule Branch: main. Or in Package.swift:
.package(url: "https://github.com/ostiums/fixkit", branch: "main")
Then add one line:
import FixKit
// SwiftUI, on the root view
WindowGroup {
ContentView()
.fixKitHost()
}
// UIKit, on the main window once it is visible
window.makeKeyAndVisible()
window.fixKitHost()
Add FixKit to every target with SwiftUI views, not only the app, and import FixKit in it; otherwise a view from that module is named where it is used, not where it is written. When more than one dynamic framework depends on FixKit, make it a framework too, so the app holds one copy:
// Tuist/Package.swift
#if TUIST
import ProjectDescription
let packageSettings = PackageSettings(productTypes: ["FixKit": .framework])
#endif
Left static, each framework holds its own copy, the views of all but one are named where they are used, and Tuist warns: "Target 'FixKit' has been linked from target 'A' and target 'B', it is a static product so may introduce unwanted side effects."
npm install --save-dev fixkit
import { FixKitHost } from 'fixkit'
export default function App() {
return (
<FixKitHost>
<RootNavigator />
</FixKitHost>
)
}
No Xcode, Podfile or app.json changes. The run commands are under React Native.
# pubspec.yaml
dependencies:
fixkit:
git:
url: https://github.com/ostiums/fixkit.git
path: flutter
import 'package:fixkit/fixkit.dart';
void main() => runApp(const FixKitHost(child: MyApp()));
With Claude Code:
claude in the project's root and run a debug build in the simulator or the emulator.The Fix queue pane lists reports and their status. It opens by itself in terminals 144+ columns wide, or with /fix-queue.
With Codex:
codex in the project's root and trust the plugin's hooks when asked (or later in /hooks).codex "FixKit".[!IMPORTANT] Untrusted hooks don't run, and FixKit starts with the Codex session's first turn. Until both happen, the app shows "FixKit is not listening". The other differences are under Codex.
For React Native and Flutter, start the agent in the folder with package.json or pubspec.yaml: that is how the plugin knows which stack the app uses.
In SwiftUI and UIKit nothing has to be marked: SwiftUI views carry their own lines, UIKit views are named after their properties.
Every view reports the line its code starts on, the app's view around it and where that view is used:
[fix r1] TransactionRow › Text · Features/Home/TransactionRow.swift:29 · used at Features/Home/HomeView.swift:60 · StaticText "−€7.40" near "Coffee" · .fixkit/reports/r1.png
Text, a press between the row's labels names its HStack..offset or a header pinned over a row is reported where it is written..fixable("name") is optional. It names the element (card.holderName › Text) and lets scripted recordings press it. Names may carry data: .fixable("transaction.amount.\(merchant)"). The name goes to the view it is on and the views written inside it, up to the nearest view of the app's own: a .fixable on a .background or a ZStack layer names that layer, not the text over it..fixScreen("Home") names the screen. With a TabView: .fixScreen(selectedTab.rawValue).The lines come from a ViewBuilder.buildExpression that FixKit adds in Debug builds: the compiler passes each view's file and line through it, and SwiftUI hands them back with the view's frame, the way Xcode Previews selects views.
Where it falls short:
return is named where it is used, and so is a view from another package.MemberImportVisibility upcoming feature needs import FixKit in every file with views.[!NOTE] To turn source lines off, depend on FixKit without its default
SourceLocationstrait:traits: []on the dependency inPackage.swift, or the same in the package's traits in Xcode. An unmarked view is then named by accessibility (with AXe) and a.fixableview by its mark's line. The feature relies on SwiftUI's underscored API for Previews, so this is also the way out if an SDK drops it.
FixKit finds the property that holds the pressed view, in the view controller, a custom view or a cell:
[fix r1] ProfileViewController.nameLabel · UILabel "Alex Morgan" · .fixkit/reports/r1.png
lazy vars and arrays (buttons[2]) are found too; a press on a button's label names the button.UILabel "Alex Morgan" · ProfileViewController screen.To get a file and line as well, mark the view:
let payButton = UIButton(configuration: .filled()).fixable("checkout.pay")
The fixkit npm package is TypeScript with no native code, so it works in Expo Go and development builds. It needs React Native 0.80+ (React 19.1) with the New Architecture.
| Project | Command |
|---|---|
| Expo Go | npx expo start --ios or --android |
| Expo development build | npx expo run:ios or npx expo run:android once, then npx expo start |
| React Native CLI | npx react-native run-ios or npx react-native run-android |
Keep Metro running: fixes go live through Fast Refresh, with no rebuild. Native changes (Podfile, Info.plist, AndroidManifest.xml, config plugins) are rebuilt with the command above.
Reports name the components, the JSX line and where the component is used:
[fix r1] WalletCard › Text · src/WalletCard.tsx:11 · used at App.tsx:15 · StaticText "Alex Morgan" · .fixkit/reports/r1.png
testIDs appear as #id.Pressable, Touchable*, Button and pressable Text don't fire while FixKit holds a press. FixKit wraps React Native's private Pressability for that, so Metro warns once about a deep import. Gesture Handler buttons aren't held.Modals and natively presented screens, nested <FixKitHost>.Try it on the example app:
cd react-native/example && npm install && npx expo start --ios # or: npx expo run:android
claude --plugin-dir ../../mod # in the same folder
The fixkit Dart package is Dart only, with no native code and no dependency beside the Flutter SDK, so nothing changes in the Podfile or the Xcode project. It needs Flutter 3.35+.
Run the app with flutter run in the iOS simulator or the Android emulator, from a terminal, VS Code or Android Studio.
Saving a file does not hot reload a Flutter app, so the agent asks for it: in Claude Code with the mod's hot_reload tool, in Codex with a POST to the receiver's /reload. Both go through the VM service flutter run serves, the one DevTools' reload button calls. A compile error comes back to the agent; for a change hot reload can't apply (initState, globals, main), the agent hot restarts the app instead.
Reports name the app's widget around the pressed one, the line of its constructor call and where that widget is used:
[fix r1] WalletCard › Text · lib/wallet_card.dart:20 · used at lib/main.dart:34 · StaticText "€12,480.50" · .fixkit/reports/r1.png
Try it on the example app:
cd flutter/example
claude --plugin-dir ../../mod # in this folder
flutter run # in a second terminal, with the iOS simulator or an Android emulator booted
With Codex, hooks start the receiver and report progress in place of the mod. Compared with Claude Code:
$TMPDIR/fixkit-codex.log.Package.swift, a React Native package.json or a Flutter pubspec.yaml. Elsewhere FixKit does nothing.codex --no-daemon get no reports./reload, even to 127.0.0.1: approve the command when Codex asks, or allow it for the session with codex -c sandbox_workspace_write.network_access=true.app (FixKit) ──POST /report──▶ receiver (node, 127.0.0.1:4747) ──AXe──▶ simulator
▲ │ └─────adb──▶ emulator
│ GET /status, POST /launched ▼
└────────── statuses ◀── Claude Code mod or Codex hooks
.contextMenu: the menu is cancelled before it opens..fixkit/reports/<id>.ax.json. On Android it reads the tree with uiautomator dump and takes the screenshot with screencap, both through adb.adb reverse on its port for every device adb lists, checked every 2 s, so the app reaches 127.0.0.1:4747 as it does in the simulator. FixKit looks for adb in FIXKIT_ADB, ANDROID_HOME, ANDROID_SDK_ROOT, on PATH, then in ~/Library/Android/sdk.codex queue, and hooks report the turn's progress.xcodebuild or Xcode's Run, a Fast Refresh, a Flutter hot reload or restart.FixKitHost in React Native and Flutter returns the app untouched outside debug mode and anywhere but iOS and Android.Tally/ is a SwiftUI wallet with four seeded UI bugs. From the repository's root:
./scripts/reset-demo.sh # restores the bugs, builds and launches Tally
claude --plugin-dir ./mod # the plugin from this checkout
| Where | Long press | Say |
|---|---|---|
| Home | the Send button | button is shifted |
| Home | the Top up button | corners don't match the others |
| Home or Cards | the card holder name | name is cut off |
| Home or Activity | a green-category amount, such as the salary | income should be green |
The bugs come from the git tag demo-start, so reset-demo.sh brings them back before each run. The scripts use the iPhone 18 Pro simulator; set SIMULATOR for another.
SwiftUI and UIKit apps can play reports from a script, for screen recordings. Enable it:
xcrun simctl spawn booted defaults write <bundle id> FixKitDirector -bool YES
Then run a server on 127.0.0.1:4748 that answers GET /next with one step as JSON, status 200:
{"press": "card.holderName", "text": "The name is cut off"}
{"at": [321, 686], "text": "Income should be green"}
{"scroll": 260}
{"defaults": {"selectedTab": "Activity"}}
press targets a .fixable name, at a point. defaults stores string values for the next launch.
[!WARNING] FixKit asks for the next step at launch and after each one, and any status other than 200 makes it ask again at once. Stop the server when the script is done.
The app shows "FixKit is not listening". No agent session holds the receiver. Start claude or codex in the project's root; in Codex, trust the plugin's hooks and send a first message. A session started with codex --no-daemon never receives reports.
A SwiftUI builder stops compiling in Debug with an error like this one:
cannot convert return expression of type 'ModifiedContent<Text, FixMarkModifier>' to return type 'Text'
Every view in a builder comes back wrapped, so a builder that must return one concrete type, such as @ViewBuilder title: () -> Text or @ViewBuilder var label: Text, no longer type-checks. Return some View there, drop @ViewBuilder where a single view is returned, or turn source lines off. A builder whose result must be Sendable gets a warning before iOS 26.
A SwiftUI view is named where it is used, not where it is written. Its body has an explicit return, or it comes from another module. In a Tuist or multi-module project, add FixKit and import FixKit to that module too (see Using Tuist).
React Native reports come without a screenshot. With several simulators of the same iOS version booted, the receiver can't tell which one runs the app. Boot one simulator per iOS version.
Android reports come without a screenshot. With several emulators online, the receiver takes the one on the app's API level. A React Native app sends its level; a Flutter app has none to send without native code, so run one emulator at a time.
An Android app shows "FixKit is not listening" while the agent runs. The app reaches the receiver through adb, and the Fix queue pane says when there is none: install the SDK's platform-tools, or point FIXKIT_ADB at adb.
A React Native or Flutter app is treated as a native one, or Codex doesn't start FixKit. Start the agent in the folder with package.json or pubspec.yaml, not above it.
./scripts/test.sh
It runs every check: plugin validation, the mod, receiver and Codex tests, the React Native tests (Node.js 22.18+), the Flutter package's tests and analysis (when flutter is installed), the Swift package's tests and a build without its default trait, and Tally's Debug and Release builds.
| Folder | Contents |
|---|---|
Sources/FixKit/, Tests/ | The Swift package and its tests |
mod/ | The Claude Code mod and Codex hooks, with the receiver in mod/server/ |
react-native/ | The fixkit npm package, with an Expo example in example/ |
flutter/ | The fixkit Dart package, with an example app in example/ |
Tally/ | The SwiftUI demo app |
scripts/ | test.sh and reset-demo.sh |