epos.json Specification
The epos.json file is the configuration file for your Epos extension. It defines what your extension does, where to load code, what permissions it needs, and how it should behave.
Basic Structure
{
"name": "My Extension",
"slug": "my-extension",
"version": "1.0.0",
"description": "A useful extension",
"icon": "icon.png",
"action": true,
"popup": { "width": 380, "height": 572 },
"config": {
"preloadAssets": false,
"allowProjectsApi": false,
"allowMissingModels": false
},
"assets": ["icon.png", "data.json"],
"targets": [
{
"matches": ["<popup>"],
"load": ["popup.js", "popup.css"]
},
{
"matches": ["*://example.com/*"],
"load": ["web.js", "web.css"]
}
],
"permissions": ["storage", "notifications"],
"manifest": null
}Fields
name
The display name of your extension. Required.
- Type:
string - Min length: 2 characters
- Max length: 45 characters
{
"name": "My Awesome Extension"
}slug
A unique identifier for your extension. Used internally for directory and database names.
- Type:
string - Min length: 2 characters
- Max length: 45 characters
- Format: lowercase letters, numbers, and hyphens; must start and end with a letter or number
- Default: Auto-generated from
nameif not provided
{
"slug": "my-extension"
}TIP
If you don't provide a slug, it's automatically generated from the name (e.g., "My Extension" → "my-extension").
version
Your extension's version number. Should follow semantic versioning.
- Type:
string - Format:
V.V.V,V.V, orV(e.g.,1.0.0,2.5,3) - Default:
0.0.1
{
"version": "1.2.3"
}description
A brief description of what your extension does.
- Type:
string | null - Max length: 132 characters
- Default:
null
{
"description": "Enhances your browsing experience with custom features"
}icon
Path to your extension's icon file. Used in the extension UI and Chrome Web Store.
- Type:
string | null - Default:
null
{
"icon": "icon.png"
}TIP
The icon is automatically added to your assets list if specified.
action
Whether to show an action button (icon) in the Chrome toolbar. Set to true for a default icon, or provide a URL for a custom icon.
- Type:
true | string | null - Default:
null(auto-detected based on targets) - Note: Automatically set to
nullif your extension has a popup or side panel
{
"action": true
}{
"action": "https://example.com/icon.png"
}popup
Configuration for the extension's popup UI.
- Type:
object - Defaults:
{ width: 380, height: 572 }
popup.width
Width of the popup in pixels.
- Type:
number - Min: 150px
- Max: 800px
- Default: 380px
popup.height
Height of the popup in pixels.
- Type:
number - Min: 150px
- Max: 572px
- Default: 572px
{
"popup": {
"width": 400,
"height": 600
}
}config
Extension configuration options.
config.preloadAssets
If true, all assets are automatically loaded when your extension starts. If false, you must call epos.assets.load() manually.
- Type:
boolean - Default:
true
{
"config": {
"preloadAssets": false
}
}config.allowProjectsApi
If true, enables the epos.projects API for programmatic project management. This is a powerful feature that should only be enabled if needed.
- Type:
boolean - Default:
false
{
"config": {
"allowProjectsApi": true
}
}config.allowMissingModels
If true, state objects can be created without being registered in epos.state.register(). Only enable if you know what you're doing.
- Type:
boolean - Default:
false
{
"config": {
"allowMissingModels": false
}
}assets
List of static files to bundle with your extension. These files are accessible via epos.assets.url() and epos.assets.get().
- Type:
string[] - Default:
[]
{
"assets": ["icon.png", "logo.svg", "data.json", "styles/theme.css"]
}TIP
Your icon is automatically added to assets if specified in the icon field.
targets
Define where your code runs. Each target specifies what code to load in specific contexts (popup, background, content scripts, etc.).
- Type:
Target[] - Required: At least one target
Target Object
{
matches: Match[]
load: string[]
}matches
Array of match patterns specifying where this target applies.
Special contexts (always available):
<popup>- Extension popup<sidePanel>- Extension side panel<background>- Background service worker
URL patterns (use for web pages):
*://example.com/*- Any page on example.com*://*.example.com/*- Any subdomain of example.com<allUrls>- All URLs*://*/*- Any http/https URL
Frame matching:
frame:*://example.com/*- Only in iframes
URL path matching:
exact:*://example.com/path- Exact URL (no query string matching by default)
{
"targets": [
{
"matches": ["<popup>"],
"load": ["popup.js"]
},
{
"matches": ["*://*.example.com/*"],
"load": ["web.js", "web.css"]
}
]
}load
Array of JavaScript and CSS files to load in this target. Order matters—files are loaded in the order specified.
File types:
.jsfiles are treated as scripts.cssfiles are treated as stylesheets
Prefixes:
lite:- Load as a lightweight script (minimal isolation)shadow:- Load CSS in shadow DOM (for web page content)
{
"load": ["popup.js", "popup.css", "lite:utils.js", "shadow:isolated.css"]
}permissions
List of browser permissions your extension needs.
- Type:
string[] - Default:
[]
Available Permissions
background- Run a background service workerstorage- Access browser storage APInotifications- Create notificationscookies- Access cookiescontextMenus- Add context menu itemsdownloads- Manage downloadsbrowsingData- Clear browsing data
Optional permissions: Prefix with optional: to request permission only when needed.
{
"permissions": ["storage", "notifications", "optional:cookies"]
}TIP
Use optional: prefix for permissions you only need in certain situations. Users can grant them through your UI.
manifest
Custom manifest overrides. Advanced feature for fine-tuning the generated Chrome manifest.
- Type:
object | null - Default:
null
{
"manifest": {
"homepage_url": "https://example.com"
}
}WARNING
This field is for advanced users. Most use cases don't need this.
Complete Example
Here's a complete epos.json with all features:
{
"name": "Todo Manager",
"slug": "todo-manager",
"version": "2.1.0",
"description": "Manage your todos across all tabs",
"icon": "icon.png",
"action": true,
"popup": {
"width": 400,
"height": 600
},
"config": {
"preloadAssets": true,
"allowProjectsApi": false,
"allowMissingModels": false
},
"assets": ["icon.png", "logo.svg", "data/defaults.json", "styles/theme.css"],
"targets": [
{
"matches": ["<popup>"],
"load": ["popup.js", "popup.css"]
},
{
"matches": ["<background>"],
"load": ["background.js"]
},
{
"matches": ["*://*.example.com/*"],
"load": ["web.js", "shadow:web.css"]
}
],
"permissions": ["storage", "notifications", "optional:contextMenus"],
"manifest": null
}Comments in epos.json
You can add comments to your epos.json file (they will be stripped during parsing):
{
// Display name
"name": "My Extension",
// Unique slug
"slug": "my-extension",
"version": "1.0.0"
// ... rest of config
}Match Pattern Reference
Context Matching
| Pattern | Description |
|---|---|
<popup> | Extension popup window |
<sidePanel> | Extension side panel |
<background> | Background service worker |
URL Matching
| Pattern | Matches |
|---|---|
*://example.com/* | example.com on any protocol |
*://*.example.com/* | example.com and subdomains |
*://*/* | Any http/https URL |
<allUrls> | Equivalent to *://*/* |
exact:*://example.com/path | Exact URL only |
frame:*://example.com/* | Only in iframes |
Examples
{
"targets": [
{
"matches": ["<popup>", "<background>"],
"load": ["ui.js"]
},
{
"matches": ["*://*.github.com/*", "*://*.gitlab.com/*"],
"load": ["code-host.js"]
},
{
"matches": ["frame:*://example.com/*"],
"load": ["iframe.js"]
}
]
}Loading Order
Files in each target are loaded in the order specified:
{
"targets": [
{
"matches": ["<popup>"],
"load": [
"vendor.js", // Loads first
"utils.js", // Then this
"components.js", // Then this
"app.js", // Finally this
"styles.css" // CSS after scripts
]
}
]
}Performance Tips
Preload vs On-Demand
{
"config": {
"preloadAssets": false // Don't preload if you have many assets
},
"assets": ["large-image.jpg", "huge-dataset.json"]
}Then load only what you need:
// Load only needed assets
await epos.assets.load('large-image.jpg')
const url = epos.assets.url('large-image.jpg')Lite JavaScript
Use lite: prefix for scripts that don't need full extension context:
{
"targets": [
{
"matches": ["*://example.com/*"],
"load": [
"lite:injected.js", // Minimal context
"content.js" // Full context
]
}
]
}Shadow CSS
Use shadow: prefix for CSS that runs in shadow DOM (isolated from page styles):
{
"targets": [
{
"matches": ["*://example.com/*"],
"load": [
"web.js",
"shadow:isolated.css" // Won't conflict with page CSS
]
}
]
}Validation Rules
Epos validates your epos.json and provides helpful error messages:
- ✅
nameis required and 2-45 characters - ✅
slugmust be lowercase with letters, numbers, and hyphens - ✅
versionmust be semantic (e.g.,1.0.0) - ✅
descriptionmax 132 characters - ✅
popup.widthbetween 150-800px - ✅
popup.heightbetween 150-572px - ✅
permissionsmust be valid permission strings - ✅
targetsmust have valid matches and load files - ✅ File paths cannot go outside project with
..
IDE Support
Most IDEs support JSON schema validation. You can add this at the top of your file:
{
"$schema": "https://epos.dev/epos.schema.json",
"name": "My Extension"
}This provides autocomplete and validation in VS Code and other modern editors.
TIP
When you save epos.json, Epos automatically regenerates your extension. Changes to config, targets, and permissions are instant!