Plugins are the primary extension mechanism in Hive. Each plugin contributes models, migrations, validators, triggers, jobs, and queries as a single coherent vertical slice — not scattered patches across core files. The four built-in plugins cover authentication, knowledge management, spaced repetition, and lexicon management.
The Plugin base class (in include/hive-api/hive/api/Plugin.hpp) provides all registration methods. After startup, close_for_changes() is called — the plugin becomes immutable at runtime.
| Registration method | What it registers | Used by |
|---|---|---|
register_model(def, validator, repository_factory) |
An entity: ModelDefinition (columns, CRUD ops, UI hints, cache config, group) + its IValidator + repository factory. The REGISTER_MODEL(model, Model, MODEL) macro wires all three. |
HTTP route generation, frontend rendering, persistence, validation |
register_migrations(MigrationScriptsPtr) |
Ordered migration scripts (V{n}__name, embedded SQL) per database dialect — REGISTER_MIGRATIONS(Plugin, SQLite) selects by configured database_type |
Applied at startup in dependency order with SHA-256 chain-hash integrity |
register_trigger(TriggerPtr) |
Before / InsteadOf / After / Around hook for one or more CRUD operations | Trigger pipeline (steps 6–9 of request lifecycle) |
register_job(JobPtr) |
A named cron-scheduled background task | CronScheduler (4 worker threads) |
register_query(QueryPtr) |
Named reusable SQL query — complex lookups shared across validators/triggers/jobs | Called via call_query(query_name, request) from triggers and jobs |
register_library_file(path) + apps |
Static frontend assets (JS/CSS libraries) and named frontend apps the plugin ships (e.g. slip_box, dictionary, repetition) |
Served by WebEndpointsGenerator; listed on the frontend landing page |
Main.cpp: register plugin factories
new CorePlugin(), new SlipBoxPlugin(), new RepetitionPlugin(), new DictionaryPlugin()
│
▼
PluginRegistry::get_plugin_names_sorted_by_dependencies()
Topological sort of declared dependency graph
Throws CyclicDependencyException — if A→B→A detected
Throws MissingDependencyException — if declared dep not registered
Result: [core, slip_box, dictionary, repetition]
│
▼
For each plugin in sorted order:
SqliteDatabaseMigration::apply_all()
· Iterate registered V{n}__name migration scripts (embedded SQL)
· Compute SHA-256 per script + rolling chain_hash
· Apply only new migrations (compare to schema history)
· On hash mismatch: throw — startup aborts
│
▼
For each plugin in sorted order:
plugin.register_models() → ModelDefinitionRegistry
plugin.register_validators() → ValidatorRegistry
plugin.register_triggers() → TriggerRegistry (sorted by priority)
plugin.register_jobs() → JobRegistry
plugin.register_queries() → QueryRegistry
plugin.close_for_changes() → Plugin becomes read-only at runtime
│
▼
HTTP route generation (one pass over ModelDefinitionRegistry)
Cron scheduler start (4 threads, ScheduledJobEntry per job)
core ◄── slip_box ◄── repetition core ◄── dictionary
The Core plugin provides platform-critical infrastructure required by every domain plugin. It is always loaded first and cannot be disabled. Source: src/hive-api/hive/plugins/core/. It is the only plugin that already ships its migrations in two SQL dialects — CoreSQLiteMigrationScripts and CorePostgreSQLMigrationScripts.
| Table | Purpose |
|---|---|
user | User accounts — username, password hash, email, display name, role, status, last login |
team / team_member | Team grouping and membership |
access_token | Short-lived bearer tokens — hashed, with expiry and revocation |
refresh_token | Session refresh tokens — hashed, rotating with rotation chain |
login_session | Tracked login sessions linking access + refresh tokens |
auth_log | Authentication events — login success/failure, logout, token refresh |
api_log | API request log (can be compiled out via MINDNET_ENABLE_API_LOG=OFF, the default) |
super_admin_log | Privileged operations log — only accessible to SuperAdmin |
history | CRUD operation history for all models (written by global After trigger; toggle via MINDNET_ENABLE_HISTORY) |
error | Server-side error tracking — type, message, timestamp |
job_entry | Persisted job definitions — name, cron, enabled, last_run, next_run |
job_run | Job execution telemetry — start, end, status, output string |
enum class UserRole : int {
Guest = 0,
Reader = 1,
Editor = 2,
Reviewer = 3,
Admin = 4,
SuperAdmin = 5,
System = 100
};
enum class UserStatus : int {
Pending = 0,
Active = 1,
Deactivated = 2,
Banned = 3,
Suspended = 4,
Deleted = 5
};
enum class RegistrationMode : int {
Free = 0,
RequiresAdminApproval = 1,
AdminAddsUsers = 2
};
UserValidator, TeamValidator, TeamMemberValidator, AccessTokenValidator, RefreshTokenValidator, LoginSessionValidator, AuthLogValidator, ApiLogValidator, SuperAdminLogValidator, HistoryValidator, ErrorValidator, JobEntryValidator, JobRunValidator — enforcing authentication logic, role hierarchy, token lifecycle, and admin-only access to operational logs.
-- V1__create_user (from CoreSQLiteMigrationScripts.cpp)
CREATE TABLE user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at DATETIME,
updated_at DATETIME,
username TEXT NOT NULL UNIQUE,
password_hash TEXT,
email TEXT,
display_name TEXT,
profile_text TEXT,
role INTEGER NOT NULL DEFAULT 0, -- UserRole (Guest=0 … System=100)
status INTEGER NOT NULL, -- UserStatus (Pending=0 … Deleted=5)
last_login DATETIME
);
CREATE INDEX idx_user_last_login ON user(last_login);
CREATE INDEX idx_user_status ON user(status);
CREATE INDEX idx_user_role ON user(role);
| Trigger name | Phase | Table | Operations | Purpose |
|---|---|---|---|---|
HistoryCommonTrigger |
After | "*" (all models) |
CRUDL | Writes a JSON snapshot of every operation to the history table. Priority 1000 (runs last); skips history, api_log, auth_log, super_admin_log and failed operations |
| Job class | Default schedule | Enabled | Purpose |
|---|---|---|---|
CleanupJob | @daily | Yes | Deletes old api_log, history (Read/List operations), login_session, and access_token records past per-type age thresholds (default 30 days) |
CleanupHistoryOrphansJob | @daily | Yes | Removes history entries whose referenced record no longer exists |
VacuumJob | @monthly | No | SQLite VACUUM — compacts the database file; run_once_when_missed=false |
TestJob | configurable | Yes | Debug/test job for scheduler verification |
CleanupSQLiteQuery · VacuumSQLiteQuery · CleanupHistoryOrphansSQLiteQuery — the SQL behind the maintenance jobs, registered as named queries so jobs stay database-agnostic.
A rich knowledge management system inspired by the Zettelkasten / Slip Box methodology. Designed for structured note-taking, knowledge graphs, and linked writing. Depends on: core. Source: src/hive-plugin-slip-box/. In the current CMake configuration it is gated behind ALLOW_LEGACY_PLUGINS (with MINDNET_ENABLE_SLIPBOX_PLUGIN=ON once legacy plugins are allowed).
| Table | Purpose |
|---|---|
note | Primary knowledge unit — title, hierarchy (parent, path, depth), importance, difficulty |
content | Note body (Markdown) stored separately, with fulltext search support |
map | Logical grouping container for notes |
link | Directional connections between notes |
tag / tag_type | Tagging with typed tag definitions |
property | Key/value properties attached to notes |
flag | Note flagging (importance, review needed, etc.) |
pinned_note | Per-user pinned notes list |
source / url | Book / web references |
wanted_note | Placeholder for planned-but-not-yet-written notes |
idea | Quick idea capture (fleeting notes) |
project / task | Structured work tracking |
term | Term index over note content |
question / test / test_attempt / test_attempt_answer | Self-testing over the knowledge base |
collection / collection_item / map_collection / map_collection_item | Curated collections of notes and maps |
alert | System alerts |
annotation | Personal annotations on notes |
-- from SlipBoxSQLiteMigrationScripts.cpp
CREATE TABLE note (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at DATETIME,
updated_at DATETIME,
map_id INTEGER NOT NULL,
parent_note_id INTEGER,
content_id INTEGER UNIQUE,
source_id INTEGER,
alias_for_note_id INTEGER,
title TEXT NOT NULL,
sibling_order INTEGER NOT NULL,
importance INTEGER DEFAULT 0,
difficulty INTEGER DEFAULT 0,
-- hierarchical metadata
path TEXT, -- e.g. '/000001/000045/000099'
depth INTEGER DEFAULT 0, -- 0=root, 1=child, ...
FOREIGN KEY (map_id) REFERENCES map(id),
FOREIGN KEY (parent_note_id) REFERENCES note(id),
FOREIGN KEY (content_id) REFERENCES content(id),
FOREIGN KEY (source_id) REFERENCES source(id)
);
The Slipbox plugin registers these static JS/CSS files for the frontend note editor:
markdown-it.min.js — Markdown renderermarkdown-it-emoji.min.js — emoji extensionhighlight.min.js — syntax highlighting| Trigger class | Phase | Purpose |
|---|---|---|
BeforeCreateNoteTrigger | Before | Prepare hierarchy fields (sibling order, content linkage) before persisting a new note |
AfterCreateUpdateNoteTrigger | After | Maintain derived data after note create/update |
UpdateNotePathAndDepthAfterTrigger | After | Recompute path and depth for the note subtree when the parent changes (backed by UpdateNotePathAndDepthSQLiteQuery) |
BeforeUpdateContentTrigger / AfterUpdateContentTrigger | Before / After | Content lifecycle — link parsing (ContentLinkParser), link synchronisation (LinkResolver/LinkSynchronizer), term maintenance around content edits |
InsteadOfReadNoteNavigationTrigger | InsteadOf | Virtual read powering graph exploration / note navigation (previous, next, parent, children, links) |
InsteadOfListTermFulltextTrigger | InsteadOf | Fulltext term search replacing the standard list operation |
InsteadOfListTagTypeFulltextTrigger | InsteadOf | Fulltext tag-type search |
AfterCreateTestAttemptTrigger / AfterCreateTestAttemptAnswerTrigger | After | Self-testing flow — select question IDs (GetQuestionIdsSQLiteQuery) and score attempts |
| Query class | Purpose |
|---|---|
FindNotesInMapSQLiteQuery | Return all notes belonging to a map (tree rendering) |
FindPreviousAndNextNoteSQLiteQuery | Resolve previous/next note for sequential navigation |
FindNextSiblingOrderSQLiteQuery | Compute the next sibling_order value under a parent |
UpdateNotePathAndDepthSQLiteQuery | Bulk-update hierarchical path/depth for a subtree |
FindTermsSQLiteQuery / FindTagTypesSQLiteQuery | Fulltext lookups backing the InsteadOf list triggers |
GetQuestionIdsSQLiteQuery | Select question IDs for a new test attempt |
One validator per model — NoteValidator, ContentValidator, MapValidator, LinkValidator, TagValidator, TagTypeValidator, PropertyValidator, FlagValidator, PinnedNoteValidator, SourceValidator, UrlValidator, WantedNoteValidator, IdeaValidator, ProjectValidator, TaskValidator, TermValidator, QuestionValidator, TestValidator, TestAttemptValidator, TestAttemptAnswerValidator, CollectionValidator, CollectionItemValidator, MapCollectionValidator, MapCollectionItemValidator, AlertValidator, AnnotationValidator, NoteNavigationValidator, TermFulltextValidator, TagTypeFulltextValidator.
| Job class | Default schedule | Purpose |
|---|---|---|
HtmlExportJob | Configurable | Exports the entire Slipbox knowledge graph as a static HTML website with navigation, link graph, and note index. Output can be deployed as a static site. |
SuperMemo-style spaced repetition system for systematic knowledge review and memorisation scheduling. Depends on: slip_box (and transitively core). Source: src/hive-plugin-repetition/.
| Table | Purpose |
|---|---|
r_session | A review session — user, map, algorithm, selected items |
r_review | Individual review — grade (0–5), response data, latency, timestamps |
r_session_metric / r_session_new | Per-session metrics and new-item tracking |
r_global_setting / r_user_setting | Global and per-user repetition configuration |
r0_state, r2_state, r4_state | Per-item scheduling state for the simpler algorithm variants |
r18_state | Per-item scheduling state for the R18 algorithm |
r18_perf_agg | Aggregated performance statistics for R18 |
r18_prediction_log | Prediction telemetry — model forecasts vs actual recall |
r18_adaptive_parameters | Adaptive per-user parameters of the R18 model |
-- from RepetitionSQLiteMigrationScripts.cpp
CREATE TABLE r_review (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at DATETIME,
updated_at DATETIME,
user_id INTEGER NOT NULL,
map_id INTEGER NOT NULL,
r_session_id INTEGER,
algorithm INTEGER NOT NULL,
note_id INTEGER,
review_date DATETIME,
grade INTEGER CHECK (grade BETWEEN 0 AND 5),
response_data TEXT, -- e.g. JSON: {"selected": [1, 3]}
notes TEXT,
started_at DATETIME, -- when started answering
ended_at DATETIME, -- when finished
latency_ms INTEGER -- response time in ms
...
);
| Trigger class | Phase | Purpose |
|---|---|---|
RSessionBeforeCreateTrigger | Before | Select the items for a new review session (backed by GetRSessionSelectedItemsSQLiteQuery) |
RReviewAfterCreateTrigger | After | After each graded review, update the per-item scheduling state (interval, next due date) |
AfterCreateDeleteFlagRepetitionTrigger | After | React to Slipbox flag create/delete — include/exclude items from repetition |
AfterUpdateContentSemanticVersionTrigger | After | Track semantic content versions so reviews reference the content revision actually studied |
| Query class | Purpose |
|---|---|
GetRSessionSelectedItemsSQLiteQuery | Select the due/new items for a session according to the chosen algorithm |
RSessionValidator, RReviewValidator, RGlobalSettingValidator, RUserSettingValidator, R0StateValidator, R2StateValidator, R4StateValidator, R18StateValidator, R18PerfAggValidator, R18PredictionLogValidator
latency_ms)/web/app_repetition.htmlNote: the Repetition plugin is gated behind ALLOW_LEGACY_PLUGINS and MINDNET_ENABLE_REPETITION_PLUGIN (OFF by default) in the current CMake configuration.
A full-featured lexicon and dictionary system with fulltext search, visit analytics, understanding tracking, review integration, and a dedicated 19-language frontend app. Depends on: core. Source: src/hive-plugin-dictionary/. This is the most actively developed domain plugin and the only one enabled in the default CMake configuration (MINDNET_ENABLE_DICTIONARY_PLUGIN=ON).
| Table | Purpose |
|---|---|
dictionary_map | Thematic map — grouping container (with emoji support in the frontend) |
dictionary_term | Primary term — title, disambiguation, definition, status, importance, difficulty, is_root |
dictionary_term_alias | Alternate names / spellings for a term |
dictionary_link | Inter-term links — since 2026 terms may link across different maps |
dictionary_source / dictionary_source_type | Reference sources with typed classification |
dictionary_url / dictionary_url_type | External URL references with typed classification |
dictionary_term_visit | Visit history per term, user, and map — feeds metrics and history windows |
dictionary_term_understanding | Per-user understanding level per term |
dictionary_note | Notes attached to dictionary entities (positioned) |
dictionary_search | Saved/advanced searches |
dictionary_review / dictionary_state_18 | Term review flow with R18-style scheduling state |
dictionary_tag / dictionary_tag_type | Typed tagging of terms |
dictionary_flag | Term flags |
dictionary_index / dictionary_index_type | Typed term indexes |
dictionary_pinned_term | Per-user pinned terms |
-- from DictionarySQLiteMigrationScripts.cpp
CREATE TABLE dictionary_term (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at DATETIME,
updated_at DATETIME,
dictionary_map_id INTEGER NOT NULL,
title TEXT NOT NULL,
disambiguation TEXT,
definition TEXT,
status INTEGER NOT NULL,
importance INTEGER NOT NULL,
difficulty INTEGER NOT NULL,
UNIQUE(dictionary_map_id, title, disambiguation),
FOREIGN KEY(dictionary_map_id)
REFERENCES dictionary_map(id)
);
CREATE INDEX idx_dictionary_term_map
ON dictionary_term(dictionary_map_id);
CREATE INDEX idx_dictionary_term_title
ON dictionary_term(title);
CREATE TABLE dictionary_term_visit (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at DATETIME,
updated_at DATETIME,
dictionary_term_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
dictionary_map_id INTEGER NOT NULL,
FOREIGN KEY(dictionary_term_id)
REFERENCES dictionary_term(id),
FOREIGN KEY(user_id) REFERENCES user(id),
FOREIGN KEY(dictionary_map_id)
REFERENCES dictionary_map(id)
);
| Trigger class | Phase | Purpose |
|---|---|---|
InsteadOfListDictionaryTermFulltextTrigger | InsteadOf | Fulltext term search with three-level autocomplete relevance scoring (exact > prefix > substring, titles ranked above aliases) |
InsteadOfListDictionaryTermSearchTrigger | InsteadOf | Advanced term search (backed by FindDictionaryTermsViaAdvancedSearchSQLiteQuery) |
InsteadOfListDictionaryTermAliasesFulltextTrigger | InsteadOf | Fulltext search over aliases, merged into autocomplete results |
InsteadOfReadDictionaryOlderTermTrigger / InsteadOfReadDictionaryNewerTermTrigger | InsteadOf | Previous/next term navigation as virtual reads |
InsteadOfReadListDictionaryTermMetricsTrigger | InsteadOf | Virtual term-metrics model — visit counts and usage analytics per term |
InsteadOfListDictionaryTermsForReviewTrigger | InsteadOf | Select terms due for review (spaced-repetition integration) |
DictionaryReviewAfterCreateTrigger | After | Update dictionary_state_18 scheduling state after each review |
BeforeCreateDictionaryNoteTrigger | Before | Compute next note position (backed by FindNextDictionaryNotePositionSQLiteQuery) |
InsteadOfListDictionarySearchesFulltextTrigger, …FlagsFulltextTrigger, …TagTypeFulltextTrigger, …IndexTypeFulltextTrigger, …SourceTypeFulltextTrigger, …UrlTypeFulltextTrigger | InsteadOf | Fulltext list overrides for the auxiliary dictionary models |
FindDictionaryTermsSQLiteQuery, FindDictionaryTermsViaAdvancedSearchSQLiteQuery, FindDictionaryTermAliasesSQLiteQuery, FindDictionaryTermMetricsSQLiteQuery, FindDictionaryTermsForReviewSQLiteQuery, FindDictionaryOlderNewerTermsSQLiteQuery, FindNextDictionaryNotePositionSQLiteQuery, FindDictionarySearchesSQLiteQuery, FindDictionaryFlagsSQLiteQuery, FindDictionaryTagTypesSQLiteQuery, FindDictionaryIndexTypesSQLiteQuery, FindDictionarySourceTypesSQLiteQuery, FindDictionaryUrlTypesSQLiteQuery
One validator per model plus dedicated validators for every virtual/fulltext model — from DictionaryTermValidator and DictionaryMapValidator through DictionaryTermMetricValidator, DictionaryTermForReviewValidator, DictionaryState18Validator, and the *Fulltext validator family. Includes input hygiene checks such as enforcing trimmed text columns.
frontend/dictionary/ — core/DictionaryApp.js, entities, enums, markdown, search, window componentsvalidate_i18n.shTermMetricsWindow and TermVisitHistoryWindow analytics windowsDictionaryHtmlExportJob/web/app_dictionary.htmlThe plugin system is the intended path for all domain extensions. The four built-in plugins (core, slip_box, repetition, dictionary) are the authoritative structural templates.
Create src/hive-plugin-<your-domain>/ mirroring the structure of an existing plugin (the Dictionary plugin is the most complete template).
src/hive-plugin-myplugin/
└── hive/plugins/myplugin/
├── MyPluginFactory.cpp
├── models/ — BaseModel subclasses + ModelDefinition
├── validators/ — IValidator per model
├── triggers/ — optional Before/After/InsteadOf triggers
├── jobs/ — optional scheduled jobs
└── migrations/
└── MyPluginSQLiteMigrationScripts.cpp
(embedded V1__…, V2__… SQL scripts)
Real pattern from RepetitionPluginFactory.cpp — the factory creates an api::Plugin with name, description, frontend apps, and explicit dependencies, then registers all contributions:
api::PluginPtr MyPluginFactory::create(
std::shared_ptr<api::RepositoryFactory>& repository_factory) const
{
auto plugin = std::make_shared<api::Plugin>(
MY_PLUGIN_NAME,
"My domain",
std::vector<std::string>{"my_app"}, // frontend apps
std::vector<std::string>{"slip_box"} // explicit deps
); // an implicit dependency on "core" is always added
REGISTER_MIGRATIONS(MyPlugin, SQLite)
// REGISTER_MODEL(model, Model, MODEL) expands to:
// plugin->register_model(models::MODEL_DEFINITION,
// std::make_shared<validators::ModelValidator>(),
// repository_factory);
REGISTER_MODEL(my_model, MyModel, MY_MODEL)
plugin->register_trigger(
std::make_shared<triggers::MyAfterCreateTrigger>());
plugin->register_query(
std::make_shared<queries::FindMyThingsSQLiteQuery>());
plugin->register_job(std::make_shared<jobs::MyCleanupJob>());
return plugin;
}
Define column constants in the ORM area, a BaseModel subclass, and a ModelDefinition with group, title column, allowed operations, and column flags (MANDATORY | TEXT, FOREIGN_KEY with automatic _id inference, etc.). Ship the matching CREATE TABLE as an embedded migration script:
add_migration("V1__create_my_model.sql", R"(
CREATE TABLE my_model (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at DATETIME,
updated_at DATETIME,
name TEXT NOT NULL,
owner_id INTEGER,
FOREIGN KEY(owner_id) REFERENCES user(id)
);
)");
Add the plugin subdirectory in the top-level CMakeLists.txt (optionally behind a feature flag like the built-in MINDNET_ENABLE_*_PLUGIN options), link the plugin library into hive_app in src/hive-app/CMakeLists.txt, and register the factory in Main.cpp following the existing plugin registration pattern.
After startup, check the complete chain:
GET /api/v1/model_definition — my_model appears/api/v1/my_modelhistory tablejob_entry table with correct cron