Platform-specific features (the full diff)
Related pages. The three-layer stack is the summarised positioning; this page is the full feature-by-feature enumeration. Honest comparisons ยง vs vanilla Label Studio is the same content shaped for the competitive question.
What this platform adds vs upstream Label Studio
AfriAnnotate is a fork of Label Studio. The labelling editor, the XML tag library, the core API contract, and most annotator-facing UI inherit from upstream. But many features that upstream gates behind their commercial Enterprise edition (or doesn't ship at all) are built natively in AfriAnnotate. This page is the diff โ useful for:
- Migrating from upstream Label Studio (what would you gain?)
- Evaluating the fork (what's the actual value-add?)
- Contributing back (these are the candidate features to upstream)
Core platform additionsโ
These are the structural features upstream LS open-source ships as stubs or doesn't ship at all โ built natively in AfriAnnotate.
Real RBAC + role permission matrixโ
Upstream Label Studio defines 30+ permission names but every one
resolves to is_authenticated โ there's no actual role logic in
the open-source edition.
AfriAnnotate ships a full six-role permission matrix:
- Owner (OW) โ top org role; can do anything
- Admin (AD) โ manage members + projects, can't transfer ownership
- Manager (MA) โ create + edit projects, manage project members
- Reviewer (RE) โ review annotations, can label too
- Annotator (AN) โ label tasks they're assigned to
- Guest (GU) โ read-only observer for stakeholders / auditors / new hires shadowing
Plus per-project role overrides (an org-level Admin can be just
an Annotator on a specific project). Plus the is_staff /
is_superuser platform-level flags layered on top.
Enforcement is at the queryset layer in DRF permission classes โ not just URL gating. See Roles for the full matrix.
Multi-organisationโ
Upstream LS open-source auto-creates one organisation on signup with the create-org endpoint hidden + no UI. Effectively single-tenant.
AfriAnnotate ships full multi-org:
- Users belong to N orgs simultaneously, switch between them via the sidebar
- Each org has its own member list, projects, branding, settings, consent library
- Cross-org access is impossible โ every database row carries an
organizationFK and is filtered at the queryset level - Platform staff can create / delete / freeze orgs from the Platform dashboard (Platform โ Orgs)
Multi-tenancy + row-level isolationโ
Beyond just having multiple orgs, every database row carries the org FK and every query in DRF is filtered by the requesting user's active org. There's no path by which a user in org A can see rows from org B by guessing IDs โ the check is at the data layer, not the URL layer.
Documented in Security model โ Multi-tenancy.
Review / QA workflowโ
Upstream open-source LS has no reviewer role and no approve/reject state on annotations. The data model has hooks but no flow.
AfriAnnotate ships a full review workflow:
- Reviewer role with its own permissions
- Per-task reviewer assignment + reviewer-stream queue
- Accept / Reject / Fix-and-accept decisions
- Reject reason (optional comment required policy)
- Tie-breaker-only mode (only surface disagreed tasks)
- Cross-project review queue at the org level
- Annotation locks post-submit + post-acceptance
See Review workflow and Review settings.
Audit log (append-only)โ
Upstream open-source LS has no audit log. AfriAnnotate ships:
- AuditEvent model that records every staff action + sensitive user action (signup, login, role change, project create / delete, consent sign / revoke, token create / revoke, etc.)
- Append-only at the DB layer โ on PostgreSQL a row-level trigger
refuses every
DELETEand everyUPDATE(the only change it lets through is theON DELETE SET NULLcascade when a user or organisation is deleted; the snapshotted actor email keeps the row meaningful). Covered by tests; see Security model โ Audit log - Combined with the consent module's hash chain, the audit surface is tamper-evident
- Filterable + exportable from Platform โ Audit log
Transactional email + verificationโ
Upstream open-source LS has an email stub โ a Django backend class exists but no templates, no sending, no DNS guidance.
AfriAnnotate ships:
- Full transactional email via any SMTP provider (Brevo / SendGrid / SES / Mailgun / Postmark โ see Email delivery)
- Per-event templates managed at Platform โ Notifications
with
{{verify_url}}/{{display_name}}/{{platform_name}}substitution - Email verification gate โ required before sign-in for all non-first users; one-shot tokens with 24h TTL
- Email change flow with re-verification on the new address
- Manual-verify escape hatch for corporate-filter-blocked users (Mark a user verified)
In-app + email notificationsโ
Upstream open-source LS has no notification system. AfriAnnotate ships:
- In-app notification center (bell icon in the top-right)
- Per-event toggles for what surfaces (consent revoked, annotation rejected, review queue grew, quota threshold crossed, auto-suspend triggered, etc.)
- Email digest option for users who'd rather batch
- Per-user overrides in Profile โ Preferences (email digest cadence + email volume) that layer on top of the platform defaults
Branding (no-rebuild rename)โ
Upstream open-source LS hardcodes "Label Studio" in many places โ rebranding requires recompiling.
AfriAnnotate ships runtime branding:
- Platform name + logo + favicon + From email all configured at Platform โ Settings โ Branding โ no rebuild required
- Propagates to browser title, login page, email subjects, mobile splash, in-app copy
- The docs site itself is rebrand-configurable via a single config
file (
docs-site/branding.config.js) โ see Hosting runbook
Rate-limit tunabilityโ
Upstream LS has hardcoded rate limits in middleware. AfriAnnotate
ships operator-tunable rate limits stored in PlatformSettings:
- Per-endpoint base + cap for the (IP, email) exponential backoff
- Tune up for high-traffic deployments
- Tune down for internal-only platforms
- Changes take effect immediately โ no deploy
Labelling tags (new XML tags)โ
Five new tags in the XML library, all marked with the platform-name badge in the Tag reference:
<AudioRecord>โ in-browser audio capture for ASR / TTS corpus collection. WebM/Opus default, configurable bitrate / sample rate / noise cancellation, optional live waveform + server-side QC checks.<AudioTextAlign>โ pair audio with transcript and align words / tokens to time positions. Word vs phoneme granularity, token vs span mode, optional autoalign via Whisper / MMS. Now supports tier hierarchies (tiers="utterance,word:utterance:subdivision") and.eafimport, giving the field-linguistic tier model that field linguists otherwise reach for a desktop tier editor for โ inside a multi-user platform.<KBRef>โ attach a concept from a curated Knowledge Base to a region (Phase 3.1). Autocomplete against label / aliases / external_id. The standard entity-linking layer above NER; the annotation stores the concept'sexternal_id+labelfor downstream normalisation.<TypedFeature>โ attach a form of dtype'd attributes (string / boolean / integer / float / link / concept_kb_ref) to a region, with feature defs managed at Project โ Settings โ Typed layers (Phase 3.1). The INCEpTION pattern generalised: NER + KB link + per-span structured metadata all on one canvas without a proprietary XML schema.<MultiModalCanvas>โ binds several time-based object tags (Audio, Video, AudioTextAlign, TimeSeries, AudioRecord) into ONE labeling surface with ONE playhead and ONE shared-region timeline (Phase 3.3). Regions drawn on the shared strip apply across every modality. The "one recording, many views" pattern common in speech, gesture, and audio-video corpus annotation.
Semantic + knowledge-base annotation (Phase 3.1)โ
Named Entity Linking + typed-attribute annotation are first-class, not add-ons.
KnowledgeBasemodel at the org level โ local (managed in-platform), remote (external autocomplete endpoint), or Wikidata backends. Entries carryexternal_id,label,aliases,description; TSV/CSV bulk import; CRUD APIs.TypedFeatureLayerat the project level โ named layer with kind (span/relation/chain/document) and a set of typed features. Each feature has adtype:string,boolean,integer,float,link, orconcept_kb_ref.<KBRef>control tag renders KB autocomplete tied to a region;<TypedFeature>renders the appropriate dtype-per-feature form (text / checkbox / number / URL / embedded KB search) on the same region.- Named Entity Linking (KB-backed) template ships in the project-
creation Labeling Interface picker โ instantiates
<Labels>,<Text>,<KBRef>, and<TypedFeature>together with the setup steps walked through in the template's details panel.
Reach for INCEpTION when the formal typed-layer constraint system (alignable-vs-referring tiers, cascading cross-layer references) is the point of the project. AfriAnnotate covers the everyday NEL + typed-attribute pattern inside a multi-modal team platform.
Multi-modal shared canvas (Phase 3.3)โ
<MultiModalCanvas> binds several time-based object tags into ONE
labelling surface. The canvas acts as the "conductor" of a sync
group โ its sync= attribute names the group, and every child tag
with the same sync= value participates. Play/pause on any child
drives all; regions drawn on the shared strip apply across every
modality; per-tag regions (Audio waveform selections, Video bounding
boxes) still work orthogonally.
Payoff for the "one recording, many views" pattern common in speech, gesture, and audio-video corpus annotation โ audio + video of a lecture, a signed conversation with gloss transcript, an interview with speaker-diarised audio all annotated in one task without switching context.
Per-project featuresโ
Audio QCโ
Audio QC โ server-side automated quality checks for audio recordings. Three tiers: cheap default-on (duration, peak, clipping, loudness LUFS, SNR, speech ratio, silence), heavy opt-in (Whisper transcript match, MMS forced alignment, DNSMOS / NISQA MOS, speaker consistency), and hard- reject corruption-level. Action on fail (warn / route to review / re-record / block). In-process or external MLBackend dispatch.
Licensing decision treeโ
Licensing โ guided 5โ8 question wizard that maps to nine SPDX outcomes (CC0, CC-BY, CC-BY-SA, CC-BY-ND, CC-BY-NC, CC-BY-NC-SA, CC-BY-NC-ND, Proprietary, Restricted). Persists the reasoning trail for dataset-provenance auditing. Surfaces in project header + export manifest.
Data securityโ
Per-project data security โ four templates (Basic / Compliance-Strict / Operational-Permissive / Custom). Toggles for offline allowed / metadata mirror / multi-device / multi-user-per-device / browser caching / cache wipe on logout / fresh session for export / annotator-action audit logging / lock-after-submit / restrict-export-to-managers / max offline cache age. Distinct from upstream's coarse-grained permissions.
Annotation behaviour extrasโ
Beyond upstream's max-annotations-per-task setting:
- Per-annotator annotation limit โ per-person cap on how much one annotator can claim (Settings โ Quality โ Annotation Limit)
- Annotations per task โ structural constraint (e.g. "โฅ 1 aspect" for ABSA, "exactly 1 span" for QA)
- Annotator-facing language โ the labelling stream renders in a project-specific language regardless of the annotator's profile preference (Settings โ General)
Per-organisation featuresโ
Consent libraryโ
Consent library โ versioned consent templates with per-purpose granular consent (GDPR Article 7 compliant), typed signatures, age attestation, country-of- residence capture, HMAC-SHA256 hash-chain audit log. Eight kinds of consent (data use, NDA, ethics, voice release, etc.).
Auto-suspend rulesโ
Auto-suspend โ automatically pause org members based on 7 rule types (inactivity, low agreement, high rejection rate, low throughput, high abandonment, quota exceeded, custom Python metric). Grace-period warnings, per-rule scope, three unsuspend paths.
Metrics dashboardsโ
Org + project metrics โ six org panels (overview, timeseries, contributors, activity, evaluations, label distribution) + four project panels (overview, timeseries, annotators, agreement). Full REST API. Pretty heavy compared to upstream's annotation-counts.
Member suspension + invite policiesโ
Suspend + invite policies โ suspension without removal (preserves audit trail), default-role- on-invite, email-domain allowlist on invites.
Per-annotator quality featuresโ
Annotator evaluation โ three related per-person quality gates:
- Calibration ramp โ new annotators warm up on ground-truth tasks before live data
- Min-score pause โ rolling agreement below threshold = auto- pause (project-level)
- Low-agreement auto-routing โ disputed tasks auto-pushed to review or re-annotated
Plus a custom agreement metric sandbox (Python) and an embedding-API config for semantic-similarity scoring.
Per-platform featuresโ
Quotasโ
Org quotas โ per-org caps on max members / max projects / max tasks. Enforcement at mutation points, 80% / 100% threshold notifications, bulk-increase API for billing- system integration.
Branding + rate limitsโ
Platform Settings โ platform name + logo
- from-email at runtime (no rebuild), per-endpoint rate limits tunable without deploy.
Audit log with append-only DB triggerโ
Platform audit log โ append-only at the DB layer (a PostgreSQL trigger refuses UPDATE and DELETE), combined with the consent module's hash chain for a tamper-evident compliance trail.
Session timeout policy (per-org)โ
Session policy โ per-org max session age + max time between activity. Different orgs on the same platform can have different security postures.
Desktop + mobile distributionโ
Mobileโ
Mobile install โ Capacitor-based thin- client app distributed via Firebase App Distribution (Android) and TestFlight (iOS). Same SPA, native shell. Architecture documented at Mobile architecture.
Desktopโ
macOS desktop โ Tauri-based wrapper, distributed as a notarized .dmg outside the Mac App Store. Less friction than TestFlight macOS for embedded- runtime apps.
Offline sync (production-hardened, Phase 4)โ
Offline sync โ desktop app's
SQLite mirror + bidirectional sync (afri_sync module). SyncMeta
shadow table for dirty-tracking, CloudProxyMiddleware for transparent
local-vs-cloud routing, conflict resolution.
Phase 4 productionised the mobile / browser side:
- Write-through IndexedDB cache for tasks, projects, annotations, and drafts. Reads go local-first; writes hit both the local cache and the outbox in one atomic step.
- Resumable offline download โ per-project checkpoint that survives cancel or crash. If a 4,000-task project download aborts at task 2,873, the next resume picks up exactly there. A Cancel button on the download UI runs a partial-cache-preserving abort path, so cancelling doesn't nuke the tasks already stored.
- Outbox backoff + idempotency โ every pending mutation gets a
client-side
unique_id; when the server hits an existing one it short-circuits with200 OKinstead of duplicating. Exponential backoff,Retry-Afterheader respected, capped max delay. No double-writes on flaky links. - Pointer-events touch parity on Audio waveforms, Video canvases, Image / Video / TimeSeries drag runners โ annotators on tablet / touch-first screens draw regions, drag playheads, and resize boxes with the same fidelity as mouse users.
- Mobile side-panels default collapsed on narrow viewports so the labelling canvas gets the screen real estate it needs.
Operator + admin toolsโ
Management commands โ
CLI commands for housekeeping: run_auto_suspend_rules,
backfill_agreement, detect_label_drift, expire_pending_invites,
send_inactivity_reminders, calculate_stats, afri_sync_pull. All
operator-runnable; most wire into Cloud Run jobs or cron.
Operator FAQ โ hoster-facing troubleshooting for cloud-deploy issues, email deliverability, build-pipeline gotchas, database scale guidance, self-hosting alternatives (AWS mapping, single-VPS minimal viable).
Distribution scaffoldingโ
End-to-end build + ship scripts for all four artifacts:
- Firebase App Distribution (Android)
- Google Play Store (Android)
- Apple TestFlight (iOS)
- Notarized macOS .dmg
Plus the hoster setup runbook tying them together.
Docs site itselfโ
The fact that the docs site rebrands cleanly via a single config
file (docs-site/branding.config.js) is itself
AfriAnnotate-specific. Every page on the site uses
AfriAnnotate / https://afriannotate.waraka.org / https://github.com/warakacommunity/afriannotate /
afriannotate.waraka.org / no-reply@label.afriannotate.org etc. โ substituted at build
time by a remark plugin. Fork the repo, edit one file, rebuild โ
the docs come out branded for your hoster.
Things we did NOT changeโ
For context, here's what stayed identical to upstream Label Studio:
- The XML tag library โ upstream apart from our additions:
<AudioRecord>,<AudioTextAlign>,<VideoRecord>,<VideoTiers>,<MultiModalCanvas>,<KBRef>,<TypedFeature> - The labelling editor (LSF) โ the embedded React widget that renders inside the browser
- The REST API for tasks / annotations / projects (we added new
endpoints under
/api/afri/,/api/consent/,/api/audio-qc/, etc., but didn't break upstream paths) - The XML labelling-config grammar (our tags inherit the same parser)
- The basic project / task / annotation data model (we added new
fields like
audio_qc_*,license,allow_offline_*, but didn't remove or rename existing ones)
The upstream Label Studio team's work is the foundation; this list is the diff.
Reading furtherโ
- Upstream Label Studio: HumanSignal/label-studio
- AfriAnnotate repo: https://github.com/warakacommunity/afriannotate
- Reference cloud: https://afriannotate.waraka.org