a love letter to tangled (android, iOS, and a search API)
1---
2title: Mobile App Reference
3updated: 2026-03-24
4---
5
6Twisted is an Ionic Vue mobile app for browsing Tangled, a git hosting platform built on the AT Protocol. It targets iOS and Android via Capacitor (no web target).
7
8## Tech Stack
9
10- **Vue 3** with TypeScript and Composition API
11- **Ionic Vue** for native-feeling UI components
12- **Capacitor** for iOS/Android builds
13- **Pinia** for state management
14- **TanStack Query** for async data with caching
15- **@atcute/client** and **@atcute/tangled** for AT Protocol XRPC
16
17TypeScript files use `.js` extensions in imports. Package management via pnpm.
18
19## Architecture
20
21Three-layer design:
22
23**Presentation** — Vue components and pages using Ionic's component library. Five-tab navigation: Home, Explore, Activity, Profile (visible tabs) plus Repo (pushed route). Repo detail uses segmented tabs: Overview, Files, Issues, PRs.
24
25**Domain** — TypeScript types modeling the app's data: UserSummary, RepoSummary, RepoDetail, RepoFile, PullRequestSummary, IssueSummary, ActivityItem. These are app-internal representations, decoupled from API response shapes.
26
27**Data** — Service layer that fetches from external sources and normalizes into domain types. The flow is: Vue component → composable → TanStack Query hook → service function → XRPC call → normalizer → domain model.
28
29## Directory Structure
30
31```sh
32src/
33 app/ — App shell, router, global config
34 core/ — Shared utilities, constants
35 services/ — API clients and data fetching
36 atproto/ — @atcute client setup, error handling
37 tangled/ — Endpoints, normalizers, TanStack Query hooks
38 domain/ — TypeScript type definitions
39 features/ — Feature modules (home, explore, repo, etc.)
40 components/ — Shared UI components
41```
42
43## Data Sources
44
45The app reads from multiple sources depending on what's needed:
46
47- **Knots** (Tangled XRPC servers) — Git data: file trees, blobs, commits, branches, diffs. Each repo is hosted on a specific knot.
48- **PDS** (Personal Data Servers) — AT Protocol records: profiles, issues, PRs, comments, stars, follows. Accessed via `com.atproto.repo.getRecord` and `com.atproto.repo.listRecords`.
49- **Twister API** — Search and index-backed summaries (when available).
50- **Constellation** — Social signal counts and backlinks (stars, followers, reactions).
51
52Knots serve XRPC endpoints for git operations. The appview at `tangled.org` returns HTML only (no JSON API), so the app goes directly to knots for git data and PDS for AT Protocol records.
53
54## Completed Features
55
56### Navigation & Shell (Phase 1)
57
58Five-tab layout with Vue Router, skeleton loaders, placeholder pages. Design system components: RepoCard, UserCard, ActivityCard, FileTreeItem, EmptyState, ErrorBoundary, SkeletonLoader, MarkdownRenderer.
59
60### Public Browsing (Phase 2)
61
62All read-only browsing works without authentication:
63
64**Repository browsing** — Metadata display, README rendering (markdown), file tree navigation, file viewer with syntax context, commit log with pagination, branch listing.
65
66**Profile browsing** — Avatar, bio, links fetched from PDS. User's repos listed.
67
68**Issues** — List view with open/closed state filter, detail view with threaded comments.
69
70**Pull Requests** — List view with status filter (open/closed/merged), detail view with comments.
71
72**Caching** — TanStack Query configured with per-data-type stale times. Persistence via Dexie (IndexedDB) — works in Capacitor's WebView on device and in the browser during local dev.
73
74## Routing
75
76The app resolves identities through AT Protocol: handle → DID (via PDS resolution) → records. For repo git data, the knot hostname is extracted from the repo's DID document.
77
78Home tab currently provides direct handle-based browsing: enter a known handle to view their profile and repos. This works without any index or search dependency.