Exocortex
unlistedby A. Kitelev
Configurable UI system for Obsidian with ontology-driven layouts
Exocortex
A semantic knowledge management system built on RDF, SPARQL, and ontology-driven architecture. Runs as an Obsidian plugin, CLI tool, or TypeScript library.
Why Exocortex
Most tools separate data from configuration: you write content in one place and configure UI, workflows, and schemas in another. Exocortex takes a different approach — Everything as Knowledge.
Your entities, their properties, UI layouts, workflows, and commands are all described as semantic data in the same Markdown files, in the same vault. Create a new entity type — and the UI adapts automatically. Define a workflow transition — and buttons appear. No code changes, no server, no vendor lock-in.
This is an evolution of the "as Code" paradigm (Infrastructure as Code, Docs as Code):
| As Code | As Knowledge (Exocortex) |
|---|---|
| Workflow as Code — CI/CD pipelines | Workflow as Knowledge — status transitions as RDF data, UI buttons generated automatically |
| Layout as Code — JSON/CSS config | Layout as Knowledge — columns, filters, sorting described semantically |
| Schema as Code — JSON Schema, Prisma | Schema as Knowledge — OWL classes and properties as files in your vault |
"As Code" describes desired system state. "As Knowledge" describes what things mean and how they relate.
Compared to existing tools:
| Exocortex | Notion | Jira | Semantic MediaWiki | Protégé | |
|---|---|---|---|---|---|
| RDF/Semantic | ✅ | — | — | ✅ | ✅ |
| File-based (git-friendly) | ✅ | — | — | — | ✅ |
| UI from ontology | ✅ | ✅ | ~ | ~ | ✅ |
| Offline-first | ✅ | ~ | — | — | ✅ |
| For knowledge workers | ✅ | ✅ | ✅ | ~ | — |
| Action layer (commands) | ✅ | ~ | ✅ | — | — |
What It Does
- Semantic knowledge graph — every piece of knowledge is an Asset with UUID, class, properties, and relationships stored as RDF triples
- SPARQL queries — ask complex questions across your entire knowledge base
- Modular ontologies (AssetSpaces) — the engine itself is domain-agnostic; every domain vocabulary ships as a separate, versioned, independently-shareable package you mount on demand. See Exo-as-SDK topology.
- Everything as Knowledge — commands, workflows, property schemas, layouts, and even plugin settings (
exo__Settingassets — see docs/explanation/settings-homoiconization.md) defined as vault assets, not hardcoded - Installable ontology packages — extend the graph by mounting an AssetSpace from any public or private GitHub repo (
assetspace-addin the CLI, Add a knowledge pack in the plugin) — no engine change required - Profile (production-ready) — vault-declared homoiconic profiles that drive on-disk AssetSpace materialization via a single Apply profile operation (mount-state strict replace). One vault, multiple contexts, selective sync. See docs/explanation/profile.md.
- ExoSync — GitHub-backed vault sync via the Exocortex: Sync command: pull → merge → push over the GitHub REST API, with structured 3-way merge and quarantine for unresolvable conflicts (a SHACL merge-gate ships in core but is not yet wired into the plugin). Works on mobile (no git binary required). See docs/how-to/exosync.md.
- UI/CLI Parity — every capability is reachable from the Obsidian plugin and the CLI; neither client holds exclusive features. The complement of homoiconicity: it keeps the invocation layer open just as homoiconicity keeps the data layer open. See VISION.md.
- Desktop / Mobile parity — every plugin command works on both desktop and mobile; none is gated desktop-only (a desktop-only dependency such as the git binary is bridged through a cross-platform path —
vault.adapter/ GitHub REST). The third member of the no-lock-in triad. See VISION.md. - Local-first — all data stays on your device, no cloud required
Quick Start
Option 1: Obsidian Plugin (via BRAT)
Best for: Visual knowledge management, daily planning, interactive exploration.
Prerequisites:
- Obsidian 1.5+ (
minAppVersionis1.5.0)
Install Exocortex via BRAT:
- Install BRAT plugin from Obsidian Community Plugins
- Open the command palette (Cmd/Ctrl + P) and run "BRAT: Plugins: Add a beta plugin for testing" — in current BRAT (2.0.8+) adding a plugin is a command-palette action, not a settings-tab button.
- Enter repository
kitelev/exocortex, then select a release from the "Select a version…" dropdown (required — the dialog ignores Add Plugin until a version is picked). - Click Add Plugin and confirm Exocortex is enabled in Community plugins.
BRAT will automatically keep the plugin updated with new releases. For the full walkthrough (Restricted Mode, Windows obsidian:// fallback, version-dropdown gotcha) see the Getting Started Guide.
Next: Follow the Getting Started Guide to bootstrap your vault and create your first Area, Project, and Task.
Note: Layouts appear in Reading Mode (Ctrl/Cmd + E).
Option 2: CLI
Best for: Automation, AI agents, batch operations.
The CLI exposes five core verbs — find, apply, query, index, validate — plus auxiliary commands (classes, create, archive, workflow, and more).
# Run via npx (or npm install -g @kitelev/exocortex-cli)
# Query your knowledge graph — core `exo:` vocabulary, works on any vault
npx @kitelev/exocortex-cli query "
PREFIX exo: <https://exocortex.my/ontology/exo#>
SELECT ?asset ?label WHERE {
?asset exo:Asset_label ?label
} LIMIT 20" --vault ~/vault
# Apply a vault-defined command (exocmd__Command) to an asset —
# e.g. a status-transition command that completes a task.
# <cmd> is the command's UUID or its exocmd__Command_cliName slug.
npx @kitelev/exocortex-cli apply <cmd> "tasks/my-task.md" --vault ~/vault --dry-run
Option 3: Core Library
Best for: Building custom applications.
import {
InMemoryTripleStore,
Triple,
IRI,
Literal,
} from "@kitelev/exocortex-core";
const store = new InMemoryTripleStore();
await store.add(
new Triple(
new IRI("obsidian://vault/tasks/my-task.md"),
new IRI("https://exocortex.my/ontology/exo#Asset_label"),
new Literal("My first task"),
),
);
// match(subject?, predicate?, object?) — undefined acts as a wildcard
const labels = await store.match(
undefined,
new IRI("https://exocortex.my/ontology/exo#Asset_label"),
undefined,
);
console.log(labels.map((t) => t.object.toString()));
See the Core API Reference for the full TypeScript API, including the SPARQL engine and vault-to-RDF conversion services.
Key Features
Asset — The Unit of Knowledge
Every piece of knowledge is a Markdown file with YAML frontmatter:
---
exo__Asset_uid: 965fd5c2-808e-4c7e-8242-e2e5d85bd996
exo__Instance_class:
- "[[3f9a1c20-0000-4000-8000-000000000001|Concept]]" # any class your ontology defines
exo__Asset_label: "Exocortex"
exo__Asset_relates:
- "[[7b2e4d80-0000-4000-8000-000000000002|PKM]]"
- "[[a1c8f600-0000-4000-8000-000000000003|Semantic Web]]"
---
Knowledge content in Markdown...
Wikilinks resolve by UID; the readable alias after
|is just for humans. Class membership (exo__Instance_class) points at whichever ontology class your mounted AssetSpaces define — the engine has no built-in domain classes of its own.
Assets are connected through typed relationships. Individual assets are information; connected assets become knowledge.
SPARQL Queries
Ask complex questions about your knowledge:
# Find every asset related to one with a given label — pure core `exo:` vocabulary
PREFIX exo: <https://exocortex.my/ontology/exo#>
SELECT ?asset ?label WHERE {
?asset exo:Asset_label ?label .
?asset exo:Asset_relates ?other .
?other exo:Asset_label "Machine Learning" .
}
Workflow Customization
Status lifecycles are not built into the engine — you define them for any class as regular vault assets, and the UI buttons follow. The plugin picks up custom workflow definitions on load and validates them (falling back to the built-in lifecycle if a definition is malformed).
See the Workflow Customization Guide for the mechanism. Concrete domain lifecycles (e.g. the EMS effort flow Draft → Backlog → Analysis → ToDo → Doing → Done) live in their own AssetSpace, not in core — see that AssetSpace's README.
Ontology-Driven Forms
Create assets with forms generated from your RDF ontology — fields appear based on rdfs:domain, types detected from rdfs:range.
Layout Code Blocks
Embed Layout definitions directly in your notes:
```exo-layout
[[8c4d2e10-0000-4000-8000-000000000004|MyLayout]]
```
Features: wikilink syntax, loading state, error handling, auto-refresh, interactive sortable tables with inline editing.
Ontology Plugins
Install community ontology packages (AssetSpaces) to extend your knowledge graph:
- CLI:
npx @kitelev/exocortex-cli assetspace-add --vault ~/vault --url https://github.com/kitelev/exoas-pmbokadds a single AssetSpace from a public GitHub URL;bootstrapsets up a fresh vault with the SDK floor. - Plugin: the Add a knowledge pack and Set up the engine palette commands do the same from Obsidian. (A first-run Setup (getting started) wizard chains them with the recommended URLs pre-filled — see the Getting Started Guide.)
Profile — Vault-Declared Context
Production-ready. Profile is the architectural cornerstone that makes Exocortex genuinely multi-context: one vault, many roles, full privacy/perf isolation per role.
A profile is a regular vault asset (exo__Profile) that declares which AssetSpaces (ontology submodule packages) are active. There is a single operation over it:
- Apply profile (
Exocortex: Apply profile) — a 2-phase-commit, mount-state strict replace. Materializes the profile's effective AssetSpaces (restore from cache or re-pull from GitHub), unmounts the rest; the TS-floor (exo) is never unmounted, whileexocmdandshared-identitiesare optional AssetSpaces. Eliminates the iPhone Obsidian Sync reindex storm; gives a physical privacy boundary between work / personal / reading contexts.
exo__AssetSpace_materialized is a runtime-derived property that reflects current on-disk state in SPARQL and the inline ✅/⏸ badge on AssetSpace pages.
See docs/explanation/profile.md for the full architectural pitch, including the UID-canon privacy model.
Command Palette
Statically registered plugin commands (all prefixed Exocortex: in the palette):
| Command | Description |
|---|---|
| Setup (getting started) | Open the guided first-run setup wizard (token → engine → registry → profiles → apply); re-openable any time |
| Edit properties | Edit the active asset's frontmatter properties |
| Reload layout | Re-render the layout on the active asset |
| Toggle layout visibility | Show or hide layouts in Reading Mode |
| Toggle archived assets visibility | Show or hide archived assets in layout tables |
| Apply profile | Apply a vault-declared profile — mount-state strict replace of the AssetSpace set (available when filesystem materialization is wired: desktop git, or mobile REST) |
| Undo last profile apply | Revert the most recent profile apply, restoring the previous mount state |
| Sync | ExoSync: pull → merge → push the materialized AssetSpace set over the GitHub REST API |
| Check sync status | Report sync divergence for the materialized AssetSpaces without writing (read-only parity check) |
| Set up the engine | Bootstrap a vault with the foundational exo AssetSpace floor |
| Add a knowledge pack | Add an AssetSpace from a public GitHub repository |
| Push current knowledge pack | Push the AssetSpace containing the active file to its remote |
| Show active profile | Report the last-applied profile |
| Remove knowledge pack (advanced) | Unmount an AssetSpace from the vault |
| Reset profile cache (advanced) | Clear the profile-switch tarball cache |
In addition, vault-defined exocmd__Command assets are registered dynamically as palette commands (the homoiconic command layer) — their set depends on the commands declared in your mounted AssetSpaces, with visibility gated by their preconditions. Asset-creation and status-transition commands come from this dynamic layer rather than being hardcoded in the engine; which ones you see depends on which AssetSpaces you mount.
Architecture
Monorepo with packages sharing a Clean Architecture core. Two runtime entry points (Obsidian Plugin and CLI) both depend on the same domain core and shared grounding-service factories; runtime-specific adapters implement common storage interfaces (IVaultAdapter / IFileSystemAdapter) so domain logic stays runtime-agnostic.
flowchart TB
subgraph Runtimes["Runtime entry points"]
Plugin["@kitelev/exocortex-obsidian-plugin<br/>(Obsidian UI, renderers, commands)"]
CLI["@kitelev/exocortex-cli<br/>(Node CLI, automation, AI agents)"]
end
subgraph Shared["Shared (runtime-agnostic) packages"]
Core["@kitelev/exocortex-core (exocortex)<br/>Domain models · RDF/SPARQL · Services"]
Services["@kitelev/exocortex-services<br/>Grounding-service factories"]
Interfaces[["IVaultAdapter · IFileSystemAdapter<br/>(ports defined in core)"]]
end
subgraph Adapters["Runtime adapters (implement ports)"]
ObsAdapter["ObsidianVaultAdapter<br/>ObsidianFileSystemAdapter<br/>(app.vault API)"]
NodeAdapter["NodeFsAdapter<br/>CachingNodeFsAdapter<br/>(fs/promises)"]
end
Plugin --> Core
Plugin --> Services
CLI --> Core
CLI --> Services
Services --> Core
Services -. depends on .-> Interfaces
Core --- Interfaces
Plugin --> ObsAdapter
CLI --> NodeAdapter
ObsAdapter -.implements.-> Interfaces
NodeAdapter -.implements.-> Interfaces
classDef runtime fill:#e3f2fd,stroke:#1565c0,color:#0d47a1;
classDef shared fill:#f3e5f5,stroke:#6a1b9a,color:#4a148c;
classDef adapter fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20;
classDef iface fill:#fff8e1,stroke:#f9a825,color:#7d5500,stroke-dasharray: 4 3;
class Plugin,CLI runtime;
class Core,Services shared;
class ObsAdapter,NodeAdapter adapter;
class Interfaces iface;
Packages
| Package | npm | Purpose |
|---|---|---|
| exocortex | Private | Core business logic, domain models, SPARQL engine, 35+ services |
| @kitelev/exocortex-obsidian-plugin | Private | Interactive UI: React components, layout renderers, palette commands, modals |
| @kitelev/exocortex-cli | @kitelev/exocortex-cli | CLI for automation, archive/unarchive, SPARQL queries, AI agent integration |
| @kitelev/exocortex-services | Private | Shared runtime-agnostic grounding-service factories (RFC 94e520da Phase 1) |
| @kitelev/exocortex-test-utils | Private | Shared test utilities, mock factories, flaky test reporter |
Technical Standards
- Clean Architecture — clear layer separation (presentation, application, domain, infrastructure)
- SOLID Principles — especially Single Responsibility
- Domain-Driven Design — knowledge domain as system center
- Semantic Web — RDF, SPARQL 1.2, OWL, RDF-Star
- Local-first — your data stays local, cloud is optional
SPARQL 1.2 Support
| Feature | Description |
|---|---|
| LATERAL Joins | Correlated subqueries for "top N per group" patterns |
| PREFIX* | Auto-import prefixes from well-known vocabularies |
| DESCRIBE Options | DEPTH and SYMMETRIC control for DESCRIBE queries |
| Directional Language Tags | RTL/LTR text direction support (@ar--rtl) |
| DateTime Arithmetic | Native date/time subtraction and duration operations |
| NORMALIZE/FOLD | Unicode normalization and case folding |
Documentation
Getting Started
- Installation Guide — Step-by-step setup
By Interface
CLI:
- Run
npx @kitelev/exocortex-cli --helpfor the full list of commands and options (find,apply,query,index,validate, and more)
Core Library:
- Core API Reference — TypeScript API
- Architecture Guide — Clean Architecture patterns
Development
git clone https://github.com/kitelev/exocortex
cd exocortex
git submodule update --init --recursive
npm install
npm run build
npm run test:all
The git submodule update --init --recursive step hydrates packages/exoas-exo and packages/exoas-exocmd — the TBox ontology + exocmd__Command fixture submodules. Tests that read fixture assets from these submodules on disk fail with an explicit error if they are missing (e.g. grounding-type-vault-fixture-parity.test.ts walks packages/exoas-exocmd/; VaultSettingsRegistry.test.ts reads packages/exoas-exo/exo/). Both submodules are public; no auth token required.
This project is developed primarily by AI agents (Claude Code, GitHub Copilot) following documented patterns. Human contributions welcome!
AI Development Resources
| Document | Purpose |
|---|---|
| CLAUDE.md | AI agent guidelines, worktree rules |
| AI Development Patterns | Patterns distilled from AI-driven development |
| Architecture Guide | Clean Architecture patterns |
Vision
For the full philosophical vision, long-term roadmap, and 42 unique IT ideas behind the project, see VISION.md.
License
MIT License — see LICENSE
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.