# Plugins and inheritFrom

Comind.work apps are assembled from layers. A base plugin provides the fields and actions every app needs. Optional plugins add capabilities like notifications, followers, or color coding. Apps add their own domain-specific schema on top. The `inheritFrom` pattern takes this further - a customer-specific app can inherit from a standard platform app and override only what it needs.

This page covers how composition works, what the base plugin provides, the full plugin catalog, and how `inheritFrom` enables vertical customization.

## Composition layers[​](#composition-layers "Direct link to Composition layers")

Every app is built from at least two layers - the base plugin and the app itself. Most apps include several plugins in between:

```
@comind/base                    <-- foundation: core fields, actions, permissions
  + @comind/plugin-follower     <-- followers field + UI
  + @comind/plugin-notification <-- notification logic (email, Slack, Teams)
  + @comind/plugin-color        <-- color coding
  + ...other plugins
  + @comind/app-task            <-- task-specific fields, actions, layouts
```

Adding a plugin is as simple as listing it in your app's `package.json` dependencies. The [compilation pipeline](/developer-guide/app-architecture/compilation-pipeline.md) handles the rest.

## How composition works[​](#how-composition-works "Direct link to How composition works")

The builder resolves and merges all layers in a four-step process:

1. **Dependency resolution** - the builder reads `package.json` dependencies, filters packages matching `@comind/(app-|block-|plugin-)`, and always includes `@comind/base`.
2. **Recursive loading** - each plugin's `fields/`, `actions/`, `views/`, and `settings/` directories are loaded from disk.
3. **Deep merge** - components merge in order: base, then plugins, then parent app (if using `inheritFrom`), then the app itself. Arrays replace rather than concatenate. Individual [fields](/developer-guide/building-blocks/fields-and-field-options.md) can override earlier definitions. The engine tracks the origin of each component so you can trace where a field or action came from.
4. **Logic combination** - `ActionLogic`, `PreconditionLogic`, and `ViewLogic` from all plugins are combined. Each plugin's methods run in sequence. See [Actions](/developer-guide/building-blocks/actions.md) and [View logic](/developer-guide/building-blocks/view-logic.md) for details on how logic classes work.

Because arrays replace rather than merge, a plugin or app can completely redefine a list of options or layout sections introduced by an earlier layer.

## The base plugin[​](#the-base-plugin "Direct link to The base plugin")

`@comind/base` provides the fields and actions that every app shares. You never need to declare it as a dependency - the builder adds it automatically.

**Fields:**

* `fields/common-fields.ts` - id, title, description, state, dates
* `fields/system-fields.ts` - creation\_date, update\_date, created\_by
* `fields/permissions-fields.ts` - ACL fields
* `fields/link-fields.ts` - parent, folder, backlinks
* `fields/imported-fields.ts` - import-related fields

**Actions:**

* `actions/core-actions.ts` - add, edit, delete, copy
* `actions/misc-actions.ts` - move, archive, and other utility actions

**Layouts:**

* `views/layouts/` - default form layout used when an app does not define its own

For the full directory structure of a plugin or app, see [Package structure](/developer-guide/app-architecture/package-structure.md).

## Plugin catalog[​](#plugin-catalog "Direct link to Plugin catalog")

The platform ships 18 plugins. Each one adds a self-contained capability that any app can opt into:

| Plugin                         | Purpose                               |
| ------------------------------ | ------------------------------------- |
| `base`                         | Core fields and actions for all apps  |
| `plugin-notification`          | Email, Slack, and Teams notifications |
| `plugin-follower`              | Watch and follow records              |
| `plugin-permission`            | Field-level and record-level ACL      |
| `plugin-reminder`              | Scheduled reminders                   |
| `plugin-recurrence`            | Recurring record creation             |
| `plugin-color`                 | Color coding                          |
| `plugin-icon`                  | Custom icons                          |
| `plugin-cover-image`           | Cover images                          |
| `plugin-contact`               | Contact info fields                   |
| `plugin-country`               | Country lookup                        |
| `plugin-custom-fields-section` | Custom fields UI section              |
| `plugin-rice-score`            | RICE prioritization scoring           |
| `plugin-task-rate`             | Task rating                           |
| `plugin-google-drive`          | Google Drive integration              |
| `plugin-cloudflare`            | Cloudflare Workers integration        |
| `plugin-demo-data`             | Demo data generation                  |
| `plugin-admin-edit`            | Admin editing capabilities            |
| `plugin-pack-basic`            | Basic plugin bundle                   |

Organizations can also create their own custom plugins following the same [package structure](/developer-guide/app-architecture/package-structure.md) conventions.

## The inheritFrom pattern[​](#the-inheritfrom-pattern "Direct link to The inheritFrom pattern")

`inheritFrom` enables a DVL (Developer Vertical Layer) override pattern. A standard platform app serves as the base, and a customer-specific app inherits from it, overriding only what it needs:

```
@comind/base                        <-- foundation
  + plugins                         <-- shared capabilities
  + @comind/app-task                <-- standard platform app
    + @customer/app-custom-task     <-- customer override (inheritFrom: "@comind/app-task")
```

The customer app declares `inheritFrom` in its `package.json`:

```
{
  "comindApp": {
    "inheritFrom": "@comind/app-task",
    "publishingAlias": "TASK"
  }
}
```

When the builder encounters `inheritFrom`, it:

1. Builds the parent app's full schema, including all of its own plugins.
2. Overlays the child app's fields, actions, layouts, and settings on top.
3. Keeps the same `publishingAlias` - the child app replaces the standard app in that workspace.

### Multi-level chains[​](#multi-level-chains "Direct link to Multi-level chains")

Inheritance can go multiple levels deep. App C inherits from B, which inherits from A. The builder resolves the full chain before applying the final overlay.

Different packages can share the same alias. For example, `TASK-for-developers`, `TASK-for-marketing`, and `TASK-for-basic` are all separate packages that use `publishingAlias: "TASK"`. Each workspace gets whichever variant is deployed to it.

This pattern keeps the standard app clean and upgradeable while giving customers full control over their vertical-specific behavior.
