Appduct lets a terminal, a test runner, or an AI agent call functions inside your running iOS, Android, React Native, Flutter or web app. Appduct calls these functions tools. Only the tools you register are reachable.
- E2E tests skip the setup. Instead of tapping through login, onboarding and an empty cart, a test calls
log_inorseed_cartand starts at the screen it's testing. - Agents can drive your app. Over MCP or the CLI, an agent can flip a feature flag, open a screen, or read some state through your tools.
- No hidden debug UI. There's no secret gesture or admin panel for someone to find.
- Release builds leave it out. By default Appduct is only in debug builds (debug and profile in Flutter). You can opt in for internal builds such as TestFlight; see Build variants.
- You add the Appduct library to your app and register tools. Each tool has a name, a description, an input schema and a handler.
- You install the
appductCLI on your computer. To connect, the CLI gives your app a link, either opened on the device for you or scanned as a QR code. The app then connects back to your computer over an encrypted connection. The connection survives reloads, backgrounding and dropped Wi-Fi. - You call tools from the terminal, a test, or an agent.
Register a tool in your app:
iOS (Swift)
import AppductCore
try Appduct.shared.register(
name: "seed_cart",
description: "Fill the cart with test items.",
inputSchema: ["type": "object", "properties": ["items": ["type": "number"]], "required": ["items"]]
) { args in
["added": (args["items"] as? NSNumber)?.intValue ?? 0]
}Android (Kotlin)
import com.callstack.appduct.Appduct
import org.json.JSONObject
Appduct.register(
name = "seed_cart",
description = "Fill the cart with test items.",
inputSchema = JSONObject("""{"type":"object","properties":{"items":{"type":"number"}},"required":["items"]}"""),
) { args ->
JSONObject().put("added", args.optInt("items"))
}Flutter (Dart)
import 'package:appduct/appduct.dart';
Appduct.instance.registerTool(
'seed_cart',
description: 'Fill the cart with test items.',
inputSchema: {
'type': 'object',
'properties': {'items': {'type': 'number'}},
'required': ['items'],
},
handler: (args, context) => {'added': (args['items'] as num).toInt()},
);React Native
import { useAppductTool } from "@appduct/react-native";
import { z } from "zod";
useAppductTool({
name: "seed_cart",
description: "Fill the cart with test items.",
inputSchema: z.object({ items: z.number() }),
handler: async ({ items }) => ({ added: items }),
});Call it from your terminal:
appduct tools call seed_cart --input '{"items":3}'-
Install the CLI:
npm install -g appduct
-
Add Appduct to your app:
- iOS, with Swift Package Manager or CocoaPods
- Android, from Maven Central
- React Native. You need a development build; Expo Go doesn't work.
- Flutter, from pub.dev
- Web, for any framework or plain JavaScript
To try it before touching your own app, run a playground app: iOS, Android or React Native.
- Documentation site: guides and reference for every platform
- CLI guide: connect to a device, list and call tools
- Use Appduct with an agent: MCP config and the agent skill
- Call tools from tests: the
appduct/clientAPI - Registering tools: schemas, long-running tools and events
- Build variants: which builds include Appduct, including web production bundles
- Security: what it protects against, trust and key rotation
- Packages and platform support
appduct is an open source project and will always remain free to use. If you think it's cool, please star it 🌟. Callstack is a group of React and React Native geeks, contact us at hello@callstack.com if you need any help with these or just want to say hi!
Like the project? ⚛️ Join the team who does amazing stuff for clients and drives React Native Open Source! 🔥
