Twisted#
Twisted is a monorepo for a Tangled mobile client and the supporting Tap-backed indexing API.
Projects#
apps/twisted: Ionic Vue client for browsing Tangled repos, profiles, issues, PRs, and indexed search resultspackages/api: Go service that consumes Tangled records through Tap, fills gaps in the public Tangled API, and serves searchdocs: top-level specs and plans, split by project underdocs/appanddocs/api
Architecture#
The app still uses Tangled's public knot and PDS APIs for canonical repo and profile data. The API project adds two complementary capabilities:
- Global search over indexed Tangled content
- Index-backed summaries for data that is hard to derive from the public API alone, such as followers
That keeps direct browsing honest while giving the client one place to ask for cross-network discovery and graph augmentation.
Development#
Use the top-level justfile for common workflows:
just dev
just build
just test
just api-run-api
To enable indexed search in the client, set VITE_TWISTER_API_BASE_URL in apps/twisted/.env.
Run Locally#
Install dependencies once from the repo root:
pnpm install
Start the Ionic/Vite app:
pnpm dev
# or: just dev
That serves the client from apps/twisted with Vite.
To run the Go API locally, make sure packages/api/.env has at least:
TURSO_DATABASE_URLTURSO_AUTH_TOKEN
Then start the API:
pnpm api:run:api
# or: just api-dev
This serves the API and search site on http://localhost:8080.
To run the indexer as well, packages/api/.env also needs:
TAP_URLTAP_AUTH_PASSWORDINDEXED_COLLECTIONS
Then start the indexer in a separate terminal:
pnpm api:run:indexer
# or: just api-run-indexer
Typical local setup is three terminals:
pnpm devpnpm api:run:apipnpm api:run:indexer
If you want the app to call the local API, set this in apps/twisted/.env:
VITE_TWISTER_API_BASE_URL=http://localhost:8080
Infrastructure Setup#
Turso#
Use one Turso database per environment, for example:
twister-devtwister-prod
Do not introduce separate app variable names for dev and prod. Always use the same variables:
TURSO_DATABASE_URLTURSO_AUTH_TOKEN
Only the values change per environment.
Example:
# Development
TURSO_DATABASE_URL=libsql://twister-dev-your-org.turso.io
TURSO_AUTH_TOKEN=...
# Production
TURSO_DATABASE_URL=libsql://twister-prod-your-org.turso.io
TURSO_AUTH_TOKEN=...
Railway#
Create or reuse one Railway project containing:
- existing
tap apirunningtwister apiindexerrunningtwister indexer
Set these shared variables on the Railway services:
TURSO_DATABASE_URLTURSO_AUTH_TOKENLOG_LEVELLOG_FORMAT
Set these API-specific variables:
HTTP_BIND_ADDRSEARCH_DEFAULT_LIMITSEARCH_MAX_LIMIT
Set these indexer-specific variables:
TAP_URLTAP_AUTH_PASSWORDINDEXED_COLLECTIONS
If you use separate Railway environments for dev and prod, keep the same variable names in both and only swap the Turso values.
First Bootstrap#
For a brand-new environment:
- Point
TURSO_DATABASE_URLandTURSO_AUTH_TOKENat the target database. - Deploy
apiandindexeron Railway. - Verify API readiness and indexer health.
- Run
twister backfillwith your seed file. - Treat the environment as search-ready only after historical backfill completes.
Docs#
- Index:
docs/README.md