In-process extensions#
A TypeScript or JavaScript module that contributes tools without a process
between it and earshot. Put one in .earshot/extensions/ for a project, or in
extensions/ under the config directory for every project. Every .ts, .mts,
.js or .mjs file there is one extension, named after its file.
// .earshot/extensions/jira.ts
export default {
tools: [
{
name: 'ticket',
description: 'Reads a Jira ticket by key',
inputSchema: { type: 'object', properties: { key: { type: 'string' } }, required: ['key'] },
readOnly: true,
async execute(input) {
return `ticket ${input.key}`;
},
},
],
};No import is needed and none is offered: earshot ships as a bundled binary, not
as a library, so a contract that required importing it would only work where
earshot happened to be resolvable. The shape is structural and validated on
load. execute may return a string or { output, isError?, title? }.
An extension is not sandboxed and cannot be. Being in-process is the whole
point of it — that is what an MCP server is for otherwise. So the boundary is
not what it may do once loaded, but whether it is loaded at all: an extension
checked into a repository you cloned stays inert until
earshot extensions trust <name> names it, recorded in .earshot/settings.local.json, which is not
committed. One under your own config directory is your own file and loads.
Its tools are namespaced and gated. jira.ts contributing ticket becomes
jira__ticket, so an extension cannot shadow bash. A tool that is not
readOnly goes through the permission gate as Extension(jira__ticket); an
extension may write the title and detail the prompt shows, but not the rule name
or target, or it could match a rule you wrote for something else. Unlike an MCP
server, a readOnly claim here is honoured — a false one is the least of what
code you already imported into the process could do.
A module that throws on import, or that does not default-export an object, costs
that extension's tools and nothing else; earshot extensions list names what is
there without importing anything untrusted.