For most of Android’s history, an app has been somewhere a person goes. They tap an icon, move through screens and eventually reach the thing they wanted to do.

Google’s idea of an Android “intelligence system” changes that journey. If it works, a person can describe an outcome and the system can ask several apps to contribute without making them the tour guide through every screen.

That sounds like a UX change. I think it is a deeper architectural one. An Android app is gaining a second interface: a visual interface for people and a capability interface for agents.

The second interface deserves at least as much care as the first.

The app is no longer the whole journey

Android has always allowed apps to cooperate. Intents, deep links, content providers, sharesheets and app actions all let one part of the system hand work to another. The new idea is not that applications can communicate. It is that the system can discover what an app is able to do, understand that capability well enough to select it and then compose it into a task the app did not design end to end.

AppFunctions is Google’s proposed boundary for that. An app describes a function, its parameters and what it returns. Android places that capability in a system registry so an agent can find and invoke it. Google compares the model to an on-device MCP server, which is a useful analogy: the application exposes tools, while the caller owns the orchestration.

The consequence is easy to underestimate. Today, a product team normally owns the path from intent to action. It chooses the screen, the copy, the order of decisions and the moment a side effect happens. In an agent-led flow, parts of that path belong to the operating system. The app may receive a valid request without the user ever seeing its home screen.

That is not a reason to resist the model. It is a reason to be precise about the contract.

Do not expose the repository; expose the product

The quickest implementation would be to place AppFunction annotations around existing services and call the job done. That is also how an internal architecture leaks into a public capability surface.

A useful function should describe something the product does for a person, not something a codebase happens to do with data. FindSuitableJobs is a capability. QueryVacanciesDao is an implementation detail. PrepareApplication expresses an outcome. UpdateApplicationEntity exposes storage.

I would put this boundary next to the use cases that already hold product rules. The AppFunction layer should be a thin Android adapter: parse and validate the request, call a stable use case, then return a small result the system can understand. It should not become a second domain layer, and it should not allow an agent to assemble low-level operations that the product would never offer directly to a user.

This matters even more in a Kotlin Multiplatform codebase. The rules for whether someone can perform an action, which fields are required and what constitutes success belong in shared product logic when they are genuinely common. AppFunctions remains an Android integration, just as another platform may adapt the same use case through its own system framework. The product truth stays in one place; the operating-system entry points stay native.

That is a healthier form of reuse than trying to share the agent protocol itself.

A function name is not a safety model

An agent can make a reasonable plan and still choose the wrong tool, misunderstand a parameter or act on stale context. Local execution removes a network hop; it does not remove risk.

I would separate functions into three broad kinds:

The distinction should be visible in the contract and in the experience. A job-search app might safely expose FindMatchingRoles. It could let an agent call PrepareApplication and return a draft. SubmitApplication is different: the application should surface the target, the material being sent and an explicit confirmation immediately before submission.

The same rule applies outside high-stakes domains. Adding groceries to a private list is not equivalent to placing the order. Drafting a message is not sending it. Finding a route is not booking a ticket. A convenient demo often collapses these pairs because the final action makes the automation look impressive. Production architecture needs to put the boundary back.

Authentication, permissions and confirmation solve different problems. Being allowed to call a function does not mean the user intended this particular effect. A robust capability also needs bounded inputs, idempotency where retries are possible, meaningful errors and an audit trail that explains what happened. If an action cannot be made safe under agent control, it should not be an AppFunction yet.

The descriptions become part of the product

Developers are used to names and documentation helping other developers. Here, the description also helps a model decide whether a function is relevant and how to invoke it. Vague language becomes runtime ambiguity.

“Manage account” is a poor tool description. Does it read the profile, change an address, cancel a subscription or delete the account? A narrower function with explicit parameters is easier for an agent to select, easier for a user to understand and much easier for a team to test.

I would review these descriptions as product copy and as API design. Examples should cover realistic phrasing, but the implementation must never depend on a prompt behaving exactly as expected. Natural language can help select the tool; types and validation must still defend its boundary.

There is also a discoverability question. Apps have traditionally competed for attention through icons, notifications and search placement. In an intelligence system, they may also compete by being the most dependable contributor to a task. A precise, reliable capability can matter even when the app’s screen is not visible. That gives engineering quality a surprisingly direct product role.

Operability is part of the feature

When a normal screen fails, the user can often describe where they were and what they tapped. An agent-composed task is harder to reconstruct. The caller may have selected several tools, retried one of them and translated an error before the person sees a result.

Teams will need traces that connect the request, function version, validation decision, user confirmation and final outcome without recording sensitive content by default. Product analytics should distinguish discovery from execution and execution from a successful user outcome. “The function returned 200” is not enough if the system chose the wrong function in the first place.

Testing also has to move above the happy-path function call. I would keep a set of representative requests, malformed parameters, permission changes, cancellation points, duplicate calls and stale-state cases. Google’s current preview provides ADB commands for listing and invoking registered functions, which is a useful starting point, but production confidence will come from the same unglamorous work as the rest of mobile engineering: contract tests, fault injection, observability and controlled rollout.

Screens still matter

It is tempting to read all this as the beginning of the end for app UI. Google’s wider announcement points in the opposite direction. AppFunctions arrives alongside more capable widgets, adaptive layouts and new surfaces across watches, cars and XR.

The likely shift is not from interface to no interface. It is from one interface carrying the entire product to several surfaces sharing the work.

An agent is good at starting from an ambiguous request and coordinating steps. A widget is good at glanceable state and a small, frequent action. A full app is still the right place to browse, compare, resolve uncertainty and build trust around a consequential decision. Good product architecture will let each surface reach the same underlying rules without pretending the surfaces are interchangeable.

For Android teams, this makes adaptive design more important, not less. The system may begin the task, but the app still needs to take over gracefully when the work becomes visual, detailed or sensitive. The hand-off cannot feel like being dropped into an arbitrary screen with no explanation of how the system got there.

I would prepare now, but ship cautiously

AppFunctions is currently an experimental preview. It targets Android 16 and later, and Gemini’s use of third-party app functions is still a private preview. The API and its adoption can change. I would not redesign a mature product around it today.

I would use the preview as an architectural test.

Take two or three real user outcomes and try to express them as narrow functions. If that is difficult, the problem may be that business rules are trapped inside ViewModels, navigation code or backend-shaped repositories. Separate read, prepare and commit paths. Make validation reusable. Decide where consent lives. Define errors that make sense outside a screen. Then invoke the functions directly and inspect what the app records.

Even if AppFunctions changes, none of that work is wasted. It leaves the product with clearer use cases, better boundaries and more testable side effects. If the intelligence-system bet succeeds, the app is ready to participate. If it does not, the architecture is still easier for people to operate.

After more than a decade of Android development, I have seen new platform APIs arrive with both grand ambition and awkward first versions. The sensible response is neither to dismiss the direction nor to wire the whole codebase into a preview.

The important question is smaller: if Android asked your app to do something on a user’s behalf, could your architecture answer clearly—and could it say no?