Extending BOB Workspace Without Code Changes¶
BOB Workspace is still structurally based on the Cadence plugin, but the goal is not to make every vault adopt Cadence's original field names. The plugin should act as a workspace shell over markdown entities, while each vault defines its own data model through schemas, Bases, and optional JSON overrides.
This guide explains the intended extension model.
Design Principle¶
The plugin has several layers. Later layers should refine or override earlier layers:
- Built-in fallback model
- Lives in
main.js. - Keeps the plugin usable in an empty vault.
- Should stay small and generic.
-
May still contain some legacy Cadence field names for compatibility.
-
Schema layer
- YAML files in
{vault.schemas.source}. - Primary source for BOB Workspace entity fields when schema support is enabled.
-
Defines field keys, labels, types, enums, required flags, and type values.
-
Base layer
.basefiles in{vault.bases}.- Defines view behavior: visible columns, filters, sort, groupBy, and special Base views.
-
The workspace should reuse these views where practical instead of duplicating view logic.
-
Custom entity layer
entities.jsonin the plugin folder next to Obsidian'sdata.json.- Lets a vault add entities or override built-in entity fields without editing plugin code.
-
Managed from Settings -> BOB Workspace -> Custom entities, or reloaded with the
Reload entities.jsoncommand. -
Import alias layer
- Maps spreadsheet/frontmatter aliases to canonical field keys.
- Useful when importing from Cadence, another CRM, or another vault.
- This is currently partly built in; long term it should be first-class configuration.
The most important rule: the vault data model should live in the vault, not in plugin code.
Entity Identity¶
Each entity type normally needs:
- A frontmatter
typevalue, such asperson,deal,invoice, ortask. - A folder or folder set where records usually live.
- A field list.
- Optional Base views.
The plugin can find entity files by:
typeFilter: matchtype: valuetypeFilters: match several frontmatter key-value pairsfolders: scan one or more foldersfolder: scan one fallback foldertypesFilter: match one of severaltypevalues
These filters are combined carefully:
foldersandtypesFilterare OR lists internally.- Different filter categories are AND-combined.
- For type-only entities such as People, avoid adding folder restrictions unless the model really requires them.
Schemas¶
Schema files are the preferred way to define BOB Workspace fields.
Example:
entity: person
label: Person
type_value: person
location_pattern: {me.people} or {client.people}
key_fields:
- name
- person_category
- company
- role
fields:
- name: type
type: string
required: true
- name: name
type: string
required: true
- name: person_category
type: string
required: false
enum:
- employee
- freelancer
- contractor
- business-contact
- personal-contact
- prospect
- other
When schemas are enabled, BOB Workspace uses these fields to enrich built-in entities. That means workbook export/import, create forms, and entity tables can use the vault's field names instead of Cadence's original names.
Bases¶
Base files should define how an entity is viewed.
Example:
filters: note.type == "person"
properties:
note.person_category:
displayName: Category
views:
- type: table
name: Business Contacts
filters:
and:
- note.person_category == "business-contact"
order:
- file.name
- person_category
- company
- role
BOB Workspace should treat Bases as the view source of truth where possible:
- selected view
- column order
- filters
- sort
- groupBy
- special Base view types
If the plugin cannot support a Base feature directly, it should show the unsupported filter/view information rather than silently pretending it is applied.
Custom Entities¶
Use entities.json when a vault does not use BOB schemas, or when a specific vault needs local overrides.
Example:
{
"deal": {
"folder": "{company.clients}",
"typeFilter": "deal",
"label": "Deal",
"plural": "Deals",
"fields": [
{ "key": "title", "label": "Title", "primary": true },
{ "key": "stage", "label": "Stage", "type": "enum", "options": ["lead", "qualified", "proposal", "won", "lost"] },
{ "key": "deal_value", "label": "Deal Value", "type": "currency" },
{ "key": "expected_close", "label": "Expected Close", "type": "date" }
],
"columns": ["title", "stage", "deal_value", "expected_close"]
}
}
Recommended uses:
- Add a new entity type.
- Override fields for a built-in entity.
- Change folder/type filters for another vault.
- Add local labels or enum values.
Avoid using entities.json for broad BOB model changes that should live in schemas.
Field Aliases¶
Field aliases are the bridge between old Cadence names, spreadsheet headers, and canonical BOB field names.
Examples:
| Incoming name | Canonical field |
|---|---|
closeBy |
expected_close |
close date |
expected_close |
value |
deal_value |
lastContact |
last_contact |
phone number |
phone |
Today, some aliases are hardcoded in the import mapper. The intended direction is to make aliases configurable per entity, for example:
{
"deal": {
"fieldAliases": {
"value": "deal_value",
"closeBy": "expected_close",
"close_date": "expected_close",
"company": "client_id"
}
}
}
Until fieldAliases is implemented as configuration, prefer using canonical field keys in schemas, Bases, and templates. Add import synonyms only for real migration needs.
Adding A New Entity¶
For a BOB vault:
- Create a schema in
{vault.schemas.source}/{entity}.yaml. - Create a Base in
{vault.bases}/{Entity}.baseif the entity needs custom views. - Add or enable a navigation item if the plugin already supports that nav group.
- Use
entities.jsononly if the schema layer is not enough. - Test create, list, workbook export, workbook import, and Base view switching.
For a non-BOB vault:
- Define the entity in
entities.json. - Point it to the vault's folder/type fields.
- Add fields and columns.
- Add aliases for old spreadsheet/frontmatter names once alias config exists.
What Requires Code¶
Most entity and field changes should not require code. Code is only needed for:
- new navigation groups or first-class surfaces
- custom non-table UI behavior
- new field widget types
- new import/export formats
- deeper Base feature support
- new commands/settings
If a change is just "this entity has a different field", it should be a schema or entities.json change, not a plugin code change.
Current Maintenance Notes¶
The plugin still contains some legacy Cadence fallback fields. This is acceptable as compatibility fallback, but BOB vaults should rely on schemas/Bases for canonical behavior.
Known cleanup direction:
- Make
fieldAliasesconfigurable. - Reduce built-in entity definitions to minimal fallbacks.
- Prefer schema-derived field definitions for import/export.
- Keep Base view support DRY rather than duplicating special views in plugin code.
- Document unsupported Base features clearly in the UI.