Add fixed Ash resources for datasets, resource definitions, dataset events, and local record projections. Expose a loopback smoke API for public synced datasets and private local-only datasets, with migrations and host-backed tests.
13 KiB
Kobold Plugin MVP PRD
Overview
Kobold is a distributed dataset and lightweight data-application plugin for Tribes OS.
It combines:
- spreadsheet-like usability
- structured CRUD data modeling
- event-sourced history
- fork/merge workflows
- composable views and forms
- lightweight deterministic formulas/macros
- distributed replication between tribes
The goal is not to recreate Excel, Airtable, or a traditional relational database directly.
The goal is to create a shared, replicable, semantically structured data layer for communities.
Kobold datasets should feel:
- approachable like spreadsheets
- structured like databases
- composable like HyperCard
- distributable like Git
- signed and lineage-aware like Nostr
The MVP focuses on:
- typed datasets
- generic CRUD
- distributed replication
- dataset forks
- deterministic formulas
- simple merge workflows
- generic UI rendering
Advanced automation, semantic federation, and collaborative realtime editing are explicitly out of scope for MVP.
⸻
Goals
Primary Goals
- Allow tribes to create structured datasets.
- Allow datasets to replicate between tribes.
- Allow datasets to be forked and modified independently.
- Allow generic CRUD interaction without custom code.
- Allow plugins to provide specialized dataset UIs.
- Support deterministic computed fields and validations.
- Preserve provenance and lineage.
- Enable embedding datasets into CMS pages and applications.
Non-Goals
The MVP does NOT attempt to provide:
- CRDT-based collaborative editing
- fully automatic conflict resolution
- arbitrary user scripting with unrestricted capabilities
- arbitrary SQL execution
- distributed transactions
- realtime multi-user spreadsheet editing
- semantic web / RDF systems
- complex workflow automation
- distributed query execution
- cross-node transactional consistency
⸻
Conceptual Model
Dataset
A dataset is a replicable collection of typed resources.
Examples:
- seed catalogs
- member directories
- inventories
- local marketplaces
- event collections
- media metadata libraries
- mapping data
- recipe databases
Datasets are:
- versioned
- signed
- forkable
- lineage-aware
- independently replicable
A dataset is the primary unit of:
- replication
- permissions
- discovery
- forking
- merging
- plugin compatibility
⸻
Resource
A resource defines a typed entity within a dataset.
Examples:
- SeedVariety
- Supplier
- Member
- Event
- Product
Resources contain:
- fields
- relationships
- computed fields
- validations
- forms
- views
⸻
Record
A record is a concrete resource instance.
Example:
resource: SeedVariety id: 01HX... fields: species: Solanum lycopersicum variety_name: Black Krim germination_days: 8
Records are event-sourced and versioned.
⸻
Relationship
Relationships connect records.
Examples:
- SeedVariety -> Supplier
- Event -> Venue
- Product -> Category
Relationships may reference records in:
- the same dataset
- external datasets
- forks
⸻
Dataset Fork
A fork creates an independently writable lineage from an existing dataset.
Forks preserve:
- origin dataset reference
- record lineage
- version ancestry
Forks may later:
- diverge permanently
- partially merge
- submit merge proposals upstream
⸻
MVP Architecture
First-Cut Architecture Decision
The first implementation should use fixed Ash resources as the durable plugin substrate and represent Kobold resources dynamically as dataset schema data.
In other words, a user-defined resource such as SeedVariety is not an Elixir module, an Ash resource module, or a dedicated Postgres table in the MVP. It is a ResourceDefinition inside a dataset, and its records are created by appending dataset events and updating a local projection.
This keeps the first cut focused on the core distributed artifact model:
- stable synced storage primitives
- append-only provenance
- generic schema-driven CRUD
- portable event envelopes
- tribe-to-tribe replication
- fork and merge lineage
Runtime-generated Ash resources, per-resource database tables, and runtime schema migrations are out of scope for the MVP unless a later optimization explicitly requires them.
Core Components
- Dataset Registry
Stores:
- dataset metadata
- ownership
- replication configuration
- schema references
- plugin compatibility
- lineage metadata
- Resource Engine
Provides:
- typed resource definitions
- CRUD operations
- validations
- relationships
- query abstraction
The MVP resource engine interprets schema metadata stored in ResourceDefinition records. It may use Ash for the fixed persistence resources, but it should not generate runtime Ash modules for user-defined dataset resources.
- Event Store
Stores append-only dataset changes.
Examples:
- record created
- record updated
- relationship added
- schema migrated
- merge accepted
The event log is the source of provenance and synchronization. Current record state is a projection of the event log, not the authoritative source of truth.
- Replication Engine
Handles:
- dataset synchronization
- event distribution
- snapshot syncing
- lineage tracking
- version checkpoints
Replication is mediated through a small tribe-to-tribe interop layer built around signed dataset manifests, schema bundles, event envelopes, snapshots, and merge proposals. Nostr is the initial transport, but the envelope format should remain transport-neutral.
- Formula Runtime
Executes deterministic formulas/macros.
Initial runtime target:
- JavaScript via QuickJS / QuickBEAM
Requirements:
- deterministic execution
- no network access
- no filesystem access
- no unrestricted host calls
- memory/time limits
- immutable inputs
- Generic CRUD UI
Provides:
- table views
- detail views
- forms
- filtering
- sorting
- relationship navigation
This acts as the default interface for any compatible dataset.
- Plugin Compatibility Layer
Allows plugins to:
- declare supported dataset types
- register specialized views/editors
- embed dataset blocks into CMS pages
⸻
Static MVP Storage Model
The first cut should use a small set of fixed plugin-owned resources:
Dataset— dataset metadata, ownership, visibility, replication mode, and lineage pointersResourceDefinition— schema-as-data for each dynamic resource in a datasetDatasetEvent— append-only signed change events and provenance metadataRecordProjection— local queryable current state derived from eventsMergeProposal— human-reviewed fork merge requests and decisions
Dataset, ResourceDefinition, DatasetEvent, and MergeProposal are the initial candidates for synced Ash resources. RecordProjection can be local-only and rebuildable at first, because it is derived from the event log.
Dataset Metadata
Example:
id: 018f2f2f... name: Community Seed Catalog owner_pubkey: npub1... type: org.tribes.scv.seed-catalog schema: scv.seed_catalog schema_version: 1.0.0 visibility: public replication: mode: public-read preferred_plugins:
- org.tribes.scv
- org.tribes.kobold
⸻
Resource Definition Example
resource: SeedVariety
fields:
species:
type: string
required: true
variety_name:
type: string
required: true
germination_days:
type: integer
computed_fields:
display_name:
formula: |
${record.species} · ${record.variety_name}
relationships:
suppliers:
type: many
target: Supplier
⸻
Formula System
Goals
Provide lightweight spreadsheet-like behavior without exposing unrestricted scripting.
Supported Use Cases
- computed fields
- validations
- formatting
- derived values
- lightweight transforms
Explicitly Unsupported in MVP
- arbitrary IO
- external HTTP requests
- unrestricted DB access
- filesystem access
- timers/background jobs
- arbitrary host execution
Example
export function compute(record) { if (record.total === 0) return null return record.sprouted / record.total }
⸻
Cross-Dataset References
Datasets may reference records from external datasets.
Example:
supplier_ref: dataset_id: 018f... resource: Supplier record_id: 01AB...
Reference modes:
- strong
- soft
- pinned-version
⸻
Replication Model
Tribe-to-Tribe Interop Layer
The MVP interop layer should be protocol-shaped and independent from UI code. It moves signed dataset artifacts between tribes and applies verified events to local projections.
Initial envelope types:
DatasetManifestSchemaBundleEventEnvelopeSnapshotMergeProposal
Initial transport adapter:
- Nostr-backed publish/subscribe and snapshot bootstrap
The interop layer is responsible for signature/hash verification, lineage checks, idempotent event application, and projection rebuild triggers. It should not know about LiveView pages or specialized dataset renderers.
Initial Replication Strategy
MVP uses:
- append-only event synchronization
- snapshot bootstrap
- latest-write-wins conflict handling where appropriate
- explicit merge proposals for divergent forks
Initial Trust Model
Datasets are signed and associated with:
- owner pubkeys
- tribe identities
- optional trust metadata
⸻
Merge Workflow
MVP merge flow:
- Dataset fork created.
- Fork diverges independently.
- Fork proposes merge upstream.
- Upstream reviews changes.
- Upstream accepts/rejects merge.
MVP merge resolution is intentionally human-centered.
No automatic semantic merge engine is required initially.
⸻
Generic UI
Table View
Provides:
- sortable columns
- filtering
- pagination
- inline editing
- relationship links
Record View
Provides:
- structured field rendering
- relationship navigation
- change history
- provenance display
Form View
Provides:
- generated forms from schema
- validation support
- formula-assisted fields
⸻
CMS Integration
Datasets should integrate with CMS pages.
Example blocks:
- dataset table block
- record detail block
- query block
- generated forms
- charts/statistics
Example:
block: type: dataset_table dataset: community_seed_catalog resource: SeedVariety filter: species: Solanum lycopersicum
⸻
Permissions
Initial permission levels:
- public read
- tribe read
- contributor write
- maintainer write
- owner/admin
Permissions apply at:
- dataset level
- resource level
- potentially record level later
⸻
Technical MVP Stack
Backend
- Elixir
- Phoenix
- LiveView
- Ash Framework
- PostgreSQL
- Oban
Formula Runtime
- QuickJS via QuickBEAM
Replication
- Nostr-based event distribution
- local SQL projections
Frontend
- LiveView-first
- plugin-rendered blocks/components
⸻
Out of Scope for MVP
The following are intentionally postponed:
- realtime collaborative editing
- CRDT synchronization
- offline-first conflict-free editing
- distributed transactions
- semantic query federation
- arbitrary plugin scripting APIs
- GraphQL federation
- AI-assisted merge resolution
- automatic ontology mapping
- advanced analytics engines
- spreadsheet compatibility import/export beyond basic CSV
⸻
Future Directions
Potential future features:
- dataset marketplaces
- trust/reputation overlays
- semantic schema mappings
- advanced merge tooling
- WASM runtimes
- visual formula builders
- AI-assisted data cleanup
- cross-dataset graph traversal
- deterministic workflow engines
- local-first mobile replicas
- dataset package registries
- public lineage explorers
⸻
First Implementation Milestones
-
Local generic dataset CRUD
- create a dataset
- define one dynamic resource with typed fields
- create, update, delete, list, and view records through generic UI
- append a
DatasetEventfor every mutation - maintain a local
RecordProjection
First-cut status: implemented as plugin-owned Ash resources and a loopback JSON smoke API. Public mutations publish through
AshNostrSync; private mutations are local-only. The LiveView remains a placeholder until the schema driven generic UI is added. -
Manual event portability
- export a dataset manifest, schema bundle, and event stream
- import them into another tribe
- rebuild the same local projection on the receiving tribe
-
Nostr-backed replication
- publish and subscribe to dataset events
- bootstrap from a snapshot when needed
- verify provenance before applying events
-
Fork and merge proposal flow
- fork a dataset lineage
- edit the fork independently
- propose a merge upstream
- review and accept or reject the event delta manually
MVP Success Criteria
The MVP is considered successful if:
- A tribe can create a typed dataset.
- Another tribe can replicate it.
- Another tribe can fork it.
- Generic CRUD works without custom code.
- Computed fields and validations work safely.
- Dataset views can be embedded into CMS pages.
- Merge proposals can be reviewed manually.
- Provenance and lineage remain inspectable.
- Plugins can provide specialized UIs.
- The system feels approachable to non-programmers.
⸻
Core Philosophy
Kobold is not merely a database.
It is a distributed, composable, lineage-aware data artifact system for communities.
The design should prioritize:
- transparency
- inspectability
- composability
- determinism
- portability
- human governance
- graceful forking
- approachable tooling
The system should feel closer to:
- shared knowledge artifacts
- living data books
- community-maintained repositories
than to traditional enterprise CRUD software.