Linkit is an open-source, Auth Mini-powered profile and instant-messaging app distributed as one Rust binary. It includes user profiles, a searchable directory, direct messages, group conversations, media attachments, direct Bark/APNs notifications, native Bot API tokens, and personal API keys that let scripts speak as a human user.
- Profiles and people directory — username, avatar, intro, and search.
- Messaging — direct and group conversations, @ mentions, image/file attachments, read state, cursor-paged history, and immediate SSE message and unread refresh.
- @ mentions — type
@in the composer to pick a conversation member or bot; the picker fuzzy-matches usernames, bot names, and your private note names, and every candidate shows its avatar, name, and your private note. Messages store mentions as<@user_id>tokens, clients render them as@username, and a mentioned member's Bark notification says they were mentioned. - Open-page links — external apps may open
/?open=profileto edit the profile or/?open=message&username=aliceto begin a direct message. - Direct Bark notifications — an iPhone running Bark binds directly to its Linkit user and receives APNs notifications without Linkit exposing a public Bark push API.
- Bilingual UI — English and Chinese interfaces, with an in-app language picker and browser-language default on first visit.
- Native Bots — each Bot is a
usersprincipal with a durable UUID, one human control owner, ansk-…bearer token, owner transfer, and token rotation. A Bot uses the same profile and conversation APIs as a user, and its owner can open a read-only view of the Bot's conversations. Any group member can add users to a group, including their own Bots; only the group owner can remove members. - User API keys — personal
uk-…tokens created on the API keys page authenticate as their creating human on the normal routes, so scripts can send messages as you; revocation is immediate. - Native iOS app — a SwiftUI client under
ios/with Auth Mini sign-in, direct and group messaging, mentions, attachments, live SSE updates and profile preferences. - Auth Mini — setup verifies its
root_user_idagainst an Auth Mini JWT; authenticated requests validate JWTs against the configured issuer and audience, then silently ensure the user's account and default profile exist. No separate registration form is required.
Download the matching archive from the latest GitHub Release, verify its SHA-256 checksum, extract it, and run ./linkit.
The app listens on 0.0.0.0:8080, serves the embedded Web UI, and creates its
private SQLite database and attachment store under ~/.linkit/. No environment
variables are required.
Open the app, enter your Auth Mini issuer, app hostname audience, public origin,
and Auth Mini subject as root_user_id, then sign in with the matching user and
initialize the instance. The default production issuer is https://auth.ntnl.io.
Every valid Auth Mini JWT on a protected API request passes through a shared
ensure operation before the route runs. New users receive a Linkit account and
a profile with an editable user_<12 hexadecimal characters> username. Existing
profiles are never overwritten; missing profiles are repaired automatically.
This works without configuring a directory token or visiting the Linkit UI.
See the provisioning contract for concurrency, collision handling and authorization boundaries.
The Root User can configure an Auth Mini user ID directory token under System → Auth Mini user sync. Linkit silently provisions missing human accounts and default profiles immediately, on startup and every 60 seconds, using only Auth Mini user IDs and without receiving other Auth Mini user data. See the configuration and API guide.
Create a Bot as its owner in the Linkit UI. The generated token is shown exactly
once and starts with sk-. The token authenticates the Bot at the normal
/api routes. For example, create a group as the Bot:
curl https://linkit.ntnl.io/api/conversations \
-H 'Authorization: Bearer sk-…' \
-H 'Content-Type: application/json' \
-d '{"title":"Fund investors","user_ids":["user-uuid"]}'A Bot can create and own groups, add or remove their members, update its own
profile, open direct conversations, and send messages through the corresponding
normal user routes. Only /api/bots and /api/user-api-keys remain
human-only control planes: Bots cannot create, rotate, transfer, or delete
Bots, and cannot manage user API keys.
The Bots page also opens a read-only perspective of a Bot's conversations. The
browser keeps the owner's Auth Mini session and adds the Bot's user ID to read
requests as ?act_as=<bot_user_id>; Linkit accepts act_as only on GET
requests and only for a Bot owned by the authenticated user.
See the Bot direct-message guide for the full creation flow, token handling, response contract, and error handling.
A human creates uk-… keys on the API keys page. A key authenticates as
the human who created it, so scripts and tools use the normal routes with that
user's own identity — the same profile, conversations, mentions, read state
and notifications as the web UI:
curl --fail-with-body https://linkit.ntnl.io/api/conversations/CONVERSATION_ID/messages \
-H 'Authorization: Bearer uk-…' \
-H 'Content-Type: application/json' \
-d '{"body":"Status report from my scripts.","attachment_ids":[],"urgent":false}'Tokens are shown exactly once, stored as hashes, and a revoked key fails on its next request. See the user API key guide for the creation flow, management API and boundaries.
Downstream products may resolve a known Auth Mini user ID to Linkit's minimal public profile: username, intro, and an optional safe avatar URL. It does not expose messages or notification data. Signed-in clients may use the separately documented bounded username search API. See the external profile API guide.
Linkit sends conversation and Bot notifications directly to Bark on iPhone through APNs. It does not expose Bark URL V1/V2 push endpoints.
Open Settings → Notifications while signed in to obtain your private Bark
Server Base URL and QR code. In Bark on iPhone, add a server and scan that QR
code. Bark calls the Base URL's /ping and /register endpoints; registration
uploads its APNs device token and Linkit binds that device to the signed-in
Linkit user who owns the Base URL.
The Base URL is a high-entropy capability, not a user ID. Linkit only stores a hash of it, redacts it from HTTP logs, and exposes it only to its owner through the authenticated settings API. Treat the URL like a device-binding secret: do not share it. Regenerating it removes existing devices and invalidates the old URL; revoking it removes both the URL and all bound devices.
When a message is created, Linkit selects only bound devices of conversation members, skips the human sender, and delivers directly to APNs with its Bark Provider Key. A Bot message can notify every bound conversation member. Clicking a delivered Bark notification opens that message's conversation at Linkit's configured public origin.
Linkit keeps only the minimal Bark iOS lifecycle surface:
GET /api/bark/b/<private-capability>/ping
GET /api/bark/b/<private-capability>/register
POST /api/bark/b/<private-capability>/register
The registration request accepts Bark's current device_key/device_token
field names and its legacy key/devicetoken names. Sending
devicetoken=deleted unbinds the matching device. The APNs Provider Key is a
root-owned runtime file, not part of this repository or release archive.
npm --prefix web ci
npm --prefix web run check
npm --prefix web run build
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets --all-features
cargo runThe frontend is built before Rust because web/dist is embedded in the binary.
main is protected by the pr-check gate. A version tag runs the release
workflow, producing Linux x86_64, Linux ARM64, and macOS ARM64 archives with
checksums. The Linux x86_64 release is checksum-verified and atomically deployed
through AWS Systems Manager to the configured EC2 instance.
Bootstrap a new Ubuntu host with deploy/bootstrap-ubuntu.sh, configure
linkit.ntnl.io DNS, obtain its TLS certificate with Certbot, and set repository
variables AWS_DEPLOY_ROLE_ARN, AWS_REGION, and EC2_INSTANCE_ID.
ios/ contains the native SwiftUI client. The Xcode project is generated with XcodeGen
from ios/project.yml; see ios/README.md for the feature set,
architecture, sign-in flow and CI details.
Root-only administration includes resource monitoring, Bark user visibility and Auth Mini directory synchronization. Setup establishes the authentication boundary. Auth Mini owns sign-in and session issuance; Linkit owns downstream authorization, profiles, conversations, Bot ownership, and message data.