Choose how to run this agent
Download Agent
Choose how you want to use this agent:
Use Security Settings Key (Recommended)
Use the API key you've already saved in Security Settings. Quick and convenient!
- No need to re-enter API key
- Works offline after download
- Centralized key management
No API key found in Security Settings. Add one now
Enter API Key Manually
Enter your API key now for this specific agent download.
- Use different key for this agent
- One-time use (not saved)
- Works offline after download
Configure Agent Encryption
Description
Based on the Android APK Starter Studio template.
What this agent can do
My Android APK Starter Studio is built from the Android APK Starter Studio template. Runs fully on your own device: llama.cpp compiled to WebAssembly, GPU-accelerated through WebGPU, with no API key and no server. After the one-time model download it works offline. Can run on OpenAI models with your own API key, encrypted in your browser. Can run on Anthropic Claude models with your own API key, encrypted in your browser.
Source Code
import base64
import html
import io
import re
import zipfile
def _build_zip(name: str, package: str, idea: str, features: str, style: str) -> str:
if not re.fullmatch(r'[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+', package):
raise ValueError('Invalid Android package ID.')
if not name.strip() or not idea.strip():
raise ValueError('App name and idea are required.')
name = name.strip()[:60]
idea = idea.strip()[:2200]
lines = [line.strip()[:120] for line in features.splitlines() if line.strip()][:8]
if not lines:
lines = ['Customize your first screen', 'Build the features in your app plan']
palette = {
'indigo': ('#4355C9', '#F4F6FF'),
'forest': ('#206B53', '#F0FAF5'),
'sunset': ('#BD593F', '#FFF5EF'),
}
accent, background = palette.get(style, palette['indigo'])
esc = lambda text: html.escape(text, quote=True).replace("'", ''')
strings = ('<?xml version="1.0" encoding="utf-8"?>\n<resources>\n'
' <string name="app_name">' + esc(name) + '</string>\n'
' <string name="description">' + esc(idea[:450]) + '</string>\n'
' <string name="features">' + esc(' • '.join(lines)) + '</string>\n'
'</resources>\n')
activity = '''package __PACKAGE__
import android.app.Activity
import android.graphics.Color
import android.os.Bundle
import android.view.Gravity
import android.widget.Button
import android.widget.LinearLayout
import android.widget.ScrollView
import android.widget.TextView
import android.widget.Toast
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val pad = (24 * resources.displayMetrics.density).toInt()
val panel = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
setPadding(pad, pad, pad, pad)
setBackgroundColor(Color.parseColor("__BACKGROUND__"))
}
fun text(value: String, size: Float, color: String): TextView = TextView(this).apply {
this.text = value
textSize = size
setTextColor(Color.parseColor(color))
setPadding(0, 0, 0, pad)
}
panel.addView(text(getString(R.string.app_name), 32f, "__ACCENT__"))
panel.addView(text(getString(R.string.description), 18f, "#213047"))
panel.addView(text("STARTER FEATURES", 13f, "__ACCENT__"))
panel.addView(text(getString(R.string.features), 18f, "#213047"))
val action = Button(this).apply {
this.text = "Get started"
setOnClickListener {
Toast.makeText(this@MainActivity, "Connect your first feature here", Toast.LENGTH_LONG).show()
}
}
panel.addView(action)
panel.gravity = Gravity.CENTER_VERTICAL
setContentView(ScrollView(this).apply { addView(panel) })
}
}
'''.replace('__PACKAGE__', package).replace('__BACKGROUND__', background).replace('__ACCENT__', accent)
app_gradle = '''plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "__PACKAGE__"
compileSdk = 35
defaultConfig {
applicationId = "__PACKAGE__"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions { jvmTarget = "17" }
}
'''.replace('__PACKAGE__', package)
manifest = '''<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:label="@string/app_name" android:theme="@android:style/Theme.Material.Light.NoActionBar" android:allowBackup="true">
<activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
'''
readme = ('# ' + name.replace('\n', ' ') + '\n\n'
'This is a compilable Kotlin Android starter UI, not a finished implementation of the requested features. The Get started button is a placeholder.\n\n'
'## Build a debug APK\n'
'Install Android SDK Platform 35, JDK 17, and Gradle 8.9. From this project folder, run:\n\n'
' gradle wrapper --gradle-version 8.9\n'
' ./gradlew assembleDebug\n\n'
'On Windows, use gradlew.bat assembleDebug. Alternatively, open the folder in Android Studio, configure Gradle 8.9, sync, and choose Build > Build APK(s).\n'
'Output: app/build/outputs/apk/debug/app-debug.apk\n\n'
'The generated ZIP intentionally does not include a Gradle wrapper JAR; the first command creates the wrapper.\n'
'The project needs an Android SDK and access to Gradle plugin dependencies for its first build.\n\n'
'## Next steps\nImplement the requested screens, persistence, permissions, and any integrations before releasing. For distribution, configure signing and create a release build.\n')
files = {
'settings.gradle.kts': 'pluginManagement { repositories { google(); mavenCentral(); gradlePluginPortal() } }\ndependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS); repositories { google(); mavenCentral() } }\nrootProject.name = "AndroidStarter"\ninclude(":app")\n',
'build.gradle.kts': 'plugins {\n id("com.android.application") version "8.6.1" apply false\n id("org.jetbrains.kotlin.android") version "2.0.21" apply false\n}\n',
'gradle.properties': 'org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\nandroid.useAndroidX=true\n',
'app/build.gradle.kts': app_gradle,
'app/src/main/AndroidManifest.xml': manifest,
'app/src/main/java/' + package.replace('.', '/') + '/MainActivity.kt': activity,
'app/src/main/res/values/strings.xml': strings,
'README.md': readme,
}
memory = io.BytesIO()
with zipfile.ZipFile(memory, 'w', compression=zipfile.ZIP_DEFLATED) as archive:
for path, content in files.items():
archive.writestr(path, content)
return base64.b64encode(memory.getvalue()).decode('ascii')
async def process_user_query(query: str) -> str:
"""Draft an Android implementation plan for the supplied app brief.
Args:
query: App name, package, idea, features, and palette.
Returns:
An actionable Android implementation plan.
"""
prompt = ('Plan this Android app for a beginner. The ZIP download is a basic Kotlin Activity UI scaffold with app title, description, feature labels, and a placeholder button. It does NOT implement the described features. Do not say an APK has been compiled. Reply in plain text, concise, with headings: MVP, Screens, Data and permissions, Build next. Avoid unsupported promises.\n\nApp brief:\n' + query[:3500])
return str(await agentop_llm.generate(prompt, globals().get('TEMPLATE_SYSTEM_PROMPT', '')))