Android app
The Android app in android/ is a native Kotlin app with Jetpack Compose and Material 3. It was built
to match the iPhone app in ios/, screen for screen, so the two apps show the same features. Like the
iPhone app, it is only an interface to the portal. It calls the same /api routes as the web app
with the same factory_session cookie. It stores no credentials, and it never calls GitHub, Daytona or
the model provider. Every request goes through the backend.
To build and install it, see Android app.
The code is in app/src/main/java/dev/matefactory/softwarefactory/.
| File | Role | iPhone counterpart |
|---|---|---|
Api.kt |
The models, ApiClient (OkHttp), the cookie jar, the events stream |
API.swift |
AppModel.kt |
Sign-in, the workspace, tabs and their back stacks, theme and reading preferences | AppModel |
Transcript.kt |
Builds the transcript from agent events, folds tool calls into steps, and parses Markdown | AgentTranscript.swift |
ThreadsScreen.kt |
The thread list and the composer | ThreadsView.swift |
ThreadScreen.kt |
The thread page: Agent, Environment, Terminal and Desktop tabs | ThreadView.swift |
EnvironmentScreen.kt |
System info, metrics, ports, processes and files | EnvironmentView.swift |
ProjectsScreen.kt |
Projects, a project’s repositories, a new project | ProjectsView.swift, NewProjectView.swift |
ReviewsScreen.kt |
Code reviews: open pull requests, automatic reviews, reviews and their findings | ReviewsView.swift |
SettingsScreen.kt |
Account, appearance (theme and reading), workspace, members, GitHub | SettingsView.swift, MembersView.swift |
The JSON keys arrive in snake_case. ApiClient converts them to camelCase before decoding, the same
way the iPhone app’s decoder does, except inside tool args, which keep the agent’s own keys.
Sign-in
Section titled “Sign-in”The app signs in with PKCE, the same as the iPhone and desktop apps (see Security model):
- Sign in with GitHub makes a PKCE verifier, saves it in the app’s preferences, and opens
/api/auth/login?app_challenge=<S256 challenge>in a Custom Tab. - The portal’s callback redirects to
softwarefactory://auth?code=….MainActivityhas an intent filter for thesoftwarefactoryscheme, and it issingleTask, so the running app receives the link. - The app posts the code and the verifier to
POST /api/auth/app/session. Thefactory_sessioncookie from the response goes intoPersistentCookieJar, which keeps it in the app’s private preferences.
The app acts on a softwarefactory://auth link only while a sign-in it started is waiting. Any website
can open such a link. Sign out calls POST /api/auth/logout and clears the cookie.
Connect a GitHub account gets a one-minute link from POST /api/github/install-link and opens it
in a Custom Tab. /api/github/setup then redirects to softwarefactory://github, and the app opens
Settings → GitHub.
The agent transcript
Section titled “The agent transcript”GET /api/threads/{id}/events is read as Server-Sent Events on an OkHttp thread. Events go into a
pending list, and the app applies the list to the transcript every 80 ms. Agent text arrives a few
characters at a time, and applying each event separately would redraw the screen too often. When the
stream ends, the app reconnects after two seconds with after set to the last seq it has.
Tool calls fold the way they do on the web. groupSteps turns each run of tool calls and thinking
that holds at least one tool call into one Entry.Steps. Replies, user messages, notices and turn
footers split runs. StepsSummary builds the line the row shows, such as “Ran 3 commands, read 1 file
· 1 failed · 15.0 s”. While a call runs, the line shows a busy dot and that call’s command, without
the time. The row is folded at first. Tapping it shows the tool and Thought rows inside it. Screenshots
from the run show under the line while it is folded.
Reviews
Section titled “Reviews”The Reviews tab sits between Projects and Settings. It shows one project at a time, the
first one until you pick another, and calls the same routes as the web’s Reviews page:
GET /api/reviews/pulls, GET /api/reviews/config and GET /api/reviews with project_id, and
POST /api/reviews for Review and Review again. The automatic review choice of each
repository is saved with PATCH /api/projects/{project_id}/repos/{repo_link_id}. While a review
runs, the tab reloads the reviews every 5 seconds. Thread opens the review’s thread in the app.
Reading
Section titled “Reading”Settings → Appearance → Reading sets the typeface (Serif, Sans or Mono), size and line spacing of agent replies, in the transcript and in review summaries and findings. The app keeps the choice in its preferences. Default size is the size replies had before; the other sizes scale it the way the web’s sizes scale its 14 px. Code blocks, tables and the rest of the app keep their size.
Terminal and desktop
Section titled “Terminal and desktop”The Terminal and Desktop tabs load the sandbox’s signed URLs in a WebView with JavaScript on. The
desktop uses the web view’s pinch zoom, because noVNC has no mobile layout. A link to a port preview
opens in the browser.
