Marvia

Sign inSign up

Adapters

One seam per external concern

A vendor SDK may only be imported inside its own adapter package. Everywhere else, the interface is the dependency.

ContractPackageReference implementation
Repositories@marvia/databaseDrizzle + PostgreSQL
AuthAdapter@marvia/authBetter Auth (Google, GitHub, email-invite)
ObjectStorageAdapter@marvia/storageCloudflare R2
KVAdapter@marvia/storageCloudflare KV
QueueAdapter@marvia/queueCloudflare Queues
EventBus@marvia/eventsin-memory (dev), queue-backed (prod)
BillingAdapter@marvia/billingnone — interfaces only
AiProviderAdapter@marvia/ai-routernone — interfaces only
ConnectorAdapter@marvia/connector-enginesupplied by extensions

Data access

Ten repositories, zero raw queries outside them

Every method takes an explicit WorkspaceId, so tenant isolation cannot be forgotten at a call site.

WorkspaceRepositoryProjectRepositoryUserRepositoryCreditRepositorySnapshotRepositoryContentRepositorySettingsRepositoryActivityRepositoryConnectorRepositoryExtensionRepositoryReportRepositoryBillingRepositoryKnowledgeRepositoryHistoryRepositoryNotificationRepositoryMarketplaceRepositoryAiRepositoryConnectorHistoryRepository

Extension SDK

defineExtension is the only entry point

Permissions are declared in the manifest and enforced at load time — a misconfigured extension can never partially install.

import { defineExtension } from "@marvia/sdk";

export default defineExtension({
  manifest: {
    id: "example",
    name: "Example",
    version: "0.1.0",
    permissions: ["workspace:read", "events:subscribe"],
  },
  setup(registrar) {
    registrar.registerNavigation({
      id: "example",
      label: "Example",
      to: "/example",
    });
    registrar.on({
      event: "snapshot.completed",
      handle: async () => {},
    });
  },
});

Registration surface

registerCardregisterReportregisterActionregisterWidgetregisterRouteregisterNavigationregisterSettingsregisterConnectoron

Extension permissions

workspace:readproject:readproject:writecredits:spendcontent:readcontent:writeconnector:readevents:subscribestorage:readstorage:writeai:invoke

Reports

Every producer emits the same schema

Core, extensions and AI agents all return this document. One renderer, one export path, one permission model for actions.

overview
metrics
cards
issues
recommendations
actions
history

Access control

Roles and permissions

Roles live on the workspace membership row. Permission checks are uniform: role + permission + workspace.

Roles

owneradmineditormemberviewerguest

Permissions

workspace.readworkspace.updateworkspace.archiveworkspace.restoreworkspace.deleteworkspace.transfermember.readmember.invitemember.updatemember.removerole.assignproject.readproject.writeproject.deletereport.readreport.generatereport.exportcredits.readcredits.consumecredits.purchaseextension.readextension.installextension.configureextension.approveconnector.readconnector.managecontent.readcontent.writecontent.publishsettings.readsettings.updatehistory.readaudit.read

Billing

Adapter interfaces only

The kernel ships no payment implementation. Providers plug in behind BillingAdapter.

telegram-manualpaddleduitkustripe (planned)xendit (planned)polar (planned)lemonsqueezy (planned)