Skip to content
WIP

This guide is a work in progress. Barry is also a work in progress.

@barry-rocks/sdk/services

Connecting to Barry’s local services: localConnection and getServiceUrl, the service registry types, environment-variable rules, and hosting configuration. A bag service uses it to find the instance it runs in and the address of a sibling service.

import { … } from "@barry-rocks/sdk/services";

Raised for every way the registry can fail to answer. The message says what to do.

  • Error

new ServiceRegistryError(message?): ServiceRegistryError

Parameter Type
message? string

ServiceRegistryError

Error.constructor

new ServiceRegistryError(message?, options?): ServiceRegistryError

Parameter Type
message? string
options? ErrorOptions

ServiceRegistryError

Error.constructor

Property Type Default value Overrides
name string "ServiceRegistryError" Error.name

What a provider reports back.

Property Type Description
generation number The routes generation this report describes.
instances? Record<string, { address?: string; error?: string; }> An address the provider’s instance reports for itself, e.g. barry-mac.tail5cb2f2.ts.net.
provider string -
reported string ISO time.
routes AppliedRoute[] -
version 1 -

What a provider reports for one route.

Property Type Description
address string Hostname for a local route, the tunnel address otherwise.
error? string -
state AppliedState -
target string | null The target the provider actually serves, or null when it serves none.
tunnel? string Tunnel name, or absent for a local route.

One entry: how a client reaches a service.

Property Type Description Overrides Inherited from
bag string - - ServiceEntry.bag
capabilities? object - - ServiceEntry.capabilities
capabilities.attachments? boolean - - -
capabilities.gating? boolean - - -
capabilities.listener? boolean - - -
capabilities.streaming? boolean - - -
displayName? string - - ServiceEntry.displayName
health? string Readiness path relative to url, e.g. “/health”. - ServiceEntry.health
id? string Optional app identity and protocol declarations for kind: “app”. - ServiceEntry.id
kind "app" - ServiceEntry.kind -
name string - - ServiceEntry.name
protocolVersion? number - - ServiceEntry.protocolVersion
url? string http://127.0.0.1:<port> for a TCP service, unix://<path> for a socket one, or deep-link for an app. Absent for a worker. - ServiceEntry.url
urlSchemes? string[] - - ServiceEntry.urlSchemes

Environment variable validation.

Services call validateEnv() at startup to fail fast on missing config.

Property Type Description
description string Human-readable description (for error messages)
name string Environment variable name
required "optional" | "always" Whether a service refuses to start without it.
services BarryService[] Services that consume this value directly.

Property Type
missing object[]
ok boolean

Browser-origin policy is separate from authentication and installation hosting policy.

Property Type Description
allowedOrigins string[] Origins allowed besides localhost: BARRY_CORS_ORIGINS, comma-separated, * matching a port.

Property Type
local? LocalPolicy
tunnels Record<string, TunnelPolicy>

Anything with Node’s listen(port, host, callback): an http.Server, or an Express app.

listen(port, hostname, callback): unknown

Parameter Type
port number
hostname string
callback () => void

unknown


Property Type
domain string
rename Record<string, string>
root? string
services string[] | "all"
via string

A readable name for a service, reached from this Mac (https://lists.home.test).

Property Type Description
hostname string Full hostname, e.g. lists.home.test.
service string Registry name of the target service.
target string Where it listens now, e.g. http://127.0.0.1:4885. Always loopback.

Property Type Description
domain? string -
instance string Which daemon or account of this provider, defined in the provider’s own config.
reach "private" | "public" -
routes TunnelRoute[] -

What core publishes to one provider.

Property Type Description
generated string ISO time.
generation number Increases on every publish; a provider reports which one it applied.
local? object -
local.domain string -
local.root? string -
local.routes LocalRoute[] -
provider string -
tunnels Record<string, PublishedTunnel> Keyed by tunnel name from hosting.yaml (phone, web).
version 1 -

One entry: how a client reaches a service.

Property Type Description
bag string -
capabilities? object -
capabilities.attachments? boolean -
capabilities.gating? boolean -
capabilities.listener? boolean -
capabilities.streaming? boolean -
displayName? string -
health? string Readiness path relative to url, e.g. “/health”.
id? string Optional app identity and protocol declarations for kind: “app”.
kind ServiceKind -
name string -
protocolVersion? number -
url? string http://127.0.0.1:<port> for a TCP service, unix://<path> for a socket one, or deep-link for an app. Absent for a worker.
urlSchemes? string[] -

Property Type Description
generated string ISO time service management wrote this.
resources Record<string, ServiceEntry> Keyed by registry name, <bag>.<service>.
version 2 -

Property Type
domain? string
gate? "none" | "access"
instance string
reach "private" | "public"
routes object[]
via string

One way in from off this Mac.

Property Type Description
address string In the provider’s own terms: a port for a private tunnel, a hostname for a public one.
gate "none" | "access" none only when the policy says so, and only for a service that authenticates its own requests.
service string -
target string -

AppliedState = "applied" | "pending" | "failed"


BarryService = "web" | "api" | "mcp" | "github-app"


HostingGate = z.infer<typeof Gate>


ServiceKind = "service" | "app" | "container" | "deployment"


ServiceName = "api" | "mcpBarry" | "slack"

The short names callers use for core services. Every other service is looked up by its own <bag>.<service> registry name. Ollama is not here: it is a token vendor, and its address is the vendor’s (registered bags’ vendor declarations).

const ENV_RULES: EnvRule[]

Startup validation rules and documented optional transport settings. Required entries block startup when absent; optional entries do not. This catalog does not enumerate every environment variable the repository reads. See docs/decisions/0046-instance-service-and-event-comments.md.


const Gate: ZodEnum<{ access: "access"; none: "none"; }>


const LOOPBACK: "127.0.0.1" = "127.0.0.1"

Services bind here. Hosting providers reach them from loopback too; see core auth.


const MCP_SERVER_KEY: "mcp.server" = "mcp.server"

The MCP server registry key; CLI compatibility aliases resolve separately. See docs/decisions/0046-instance-service-and-event-comments.md.

appEntry(appIdOrName, path?): AppRecord

Look up an app by id, name, or .. Throws when not found.

Parameter Type
appIdOrName string
path string

AppRecord


appliedPath(provider): string

Parameter Type
provider string

string


assignedPort(env?): number

The port service management assigned, from PORT.

Refuses to guess: a service started without PORT was not started by barry up, and a fallback number is exactly how a second copy of a service ends up answering on the real one’s port.

Parameter Type Default value
env ProcessEnv process.env

number


bagDataDir(bag, options?): string

<app support>/data/<bag>, created 0700. Extensions use + in place of /.

Parameter Type
bag string
options? { create?: boolean; }
options.create? boolean

string


bagLogsDir(bag): string

<logs>/<bag>. Not created.

Parameter Type
bag string

string


bagSegment(bag): string

A registered bag name as one directory segment; extensions use +.

Parameter Type
bag string

string


barryAdaptersPath(): string

<app support>/adapters.json, the harness adapters this installation has.

string


barryAppSupportDir(): string

~/Library/Application Support/Barry, or $BARRY_HOME/app-support.

string


barryArchivesDir(): string

string


barryBackupsDir(): string

string


barryCacheDir(): string

~/Library/Caches/Barry, or $BARRY_HOME/cache.

string


barryConfigDir(): string

$XDG_CONFIG_HOME/barry (default ~/.config/barry), or $BARRY_HOME/config.

string


barryCurrentDir(): string

string


barryEnvPath(): string

<app support>/env, the instance’s secrets file.

string


barryLogsDir(): string

~/Library/Logs/Barry, or $BARRY_HOME/logs.

string


barryModelProvidersPath(): string

Explicitly selected model adapter packages for this installation.

string


barryReleasesDir(): string

string


barryRunDir(): string

$TMPDIR/barry-<hash of the instance root>, for sockets and pid files.

string


barryStoresDir(): string

string


corsOrigins(): string[]

Extra origins allowed by BARRY_CORS_ORIGINS, beyond localhost.

Exported so a service can log what it actually allows at startup: CORS failures show up in a browser as an opaque network error, and “localhost only” in the boot log is usually the answer.

string[]


ensureInstanceSecret(path?): boolean

Generate BARRY_SECRET into the instance env when it has none; true when it did.

Every service and client authenticates with it, so an instance without one starts nothing. barry setup calls this for the installed instance and barry up for a contributor or test one, which its first up creates. Reads the file only, never the calling shell: a shell exporting an old secret would otherwise leave the file without one, and service management launchd starts has no shell.

Parameter Type
path string

boolean


getAppUrl(appIdOrName, options?): string

URL or deep link to open a registered app.

Parameter Type
appIdOrName string
options { path?: string; session?: string; }
options.path? string
options.session? string

string


getHostingConfig(): HostingConfig

HostingConfig


getServicePort(service): number

The port service listens on now. See getServiceUrl.

Parameter Type
service ServiceName

number


getServiceUrl(service, host?): string

Where service listens, read from this instance’s registry on every call.

Per call rather than once at startup: a service moved with barry service port is reached at its new address by the very next request, and nothing that talks to it has to restart. The read costs a stat. Throws when the service is not registered, rather than falling back to a number that belongs to some other instance.

Parameter Type Default value
service ServiceName undefined
host string "localhost"

string


hostEnvironment(source?): Record<string, string>

Parameter Type Default value
source Readonly<Record<string, string | undefined>> process.env

Record<string, string>


hostingDir(): string

<app support>/hosting.

string


hostingPolicyPath(): string

string


installationPath(path): string

Parameter Type
path string

string


installationRoot(): string

string


instanceEnvIsPrivate(path?): boolean

Whether the instance env is readable by anyone but its owner.

Parameter Type
path string

boolean


instanceEnvValue(key, path?): string | undefined

Read one value from the selected instance’s private file.

Parameter Type
key string
path? string

string | undefined


instanceId(): string

8-hex-char id for this instance, derived from its root. Unique per instance, stable across calls.

string


listApps(path?): AppRecord[]

All registered apps from the service registry.

Parameter Type
path string

AppRecord[]


listenOnAssignedPort(target, env?): Promise<Server<typeof IncomingMessage, typeof ServerResponse>>

Listen on the assigned port, on loopback. Resolves with the server once it is accepting connections; rejects, naming the port, if it cannot bind.

Accepts an Express app as well as a server: app.listen returns the server it creates, and that is what this resolves with.

Parameter Type Default value
target Listenable undefined
env ProcessEnv process.env

Promise<Server<typeof IncomingMessage, typeof ServerResponse>>


localConnection(options?): Promise<ConnectOptions>

Connect through the selected instance’s registry and installation credential references.

Parameter Type
options ConnectOptions

Promise<ConnectOptions>


originAllowed(origin, allowed): boolean

The one origin matcher every service shares (SDK-21). A literal entry must match exactly; a * is a PORT wildcard only — http://host:* escapes every regex metacharacter and maps * to \d+, so the dots stay literal and the wildcard cannot widen to another host. A drifted copy that mapped * to .* with unescaped dots was quietly less protected while looking identical.

Parameter Type
origin string
allowed string

boolean


parseEnvFile(text): Record<string, string>

Parse KEY=VALUE lines. Blank lines and # comments are skipped; one layer of quotes is removed.

Parameter Type
text string

Record<string, string>


parseHostingPolicy(text, label?): HostingPolicy

Parse and validate the policy’s shape. Throws naming the offending key.

Parameter Type Default value
text string undefined
label string "hosting.yaml"

HostingPolicy


parseServiceRegistry(text, path?): ServiceRegistryFile

Validate a registry’s text. Exported for tests and for service management’s own round-trip check.

Parameter Type Default value
text string undefined
path string "<registry>"

ServiceRegistryFile


publishRoutes(file): void

Core: publish a provider’s routes in one step.

Parameter Type
file RoutesFile

void


readApplied(provider): AppliedFile | null

Core: what a provider last reported, or null if it never has.

Parameter Type
provider string

AppliedFile | null


readHostingPolicy(path?): HostingPolicy | null

The installation’s policy, or null when it has none: then nothing is exposed beyond loopback.

Parameter Type
path string

HostingPolicy | null


readInstanceEnv(path?): Record<string, string>

Every key in the instance env. Absent file means none.

Parameter Type
path string

Record<string, string>


readRoutes(provider): RoutesFile

Provider: read what core published.

Throws on a missing or unreadable file rather than returning no routes. A provider that reconciled “no routes” would tear down every name and tunnel it serves because of one bad read.

Parameter Type
provider string

RoutesFile


readServiceRegistry(path?): ServiceRegistryFile

The registry as service management last wrote it.

Re-read whenever the file’s inode, mtime or size changes, so the cost of looking an address up on every call is one stat. The inode is what catches a rewrite that kept the same size within the same clock tick: every write renames a new file into place.

Parameter Type
path string

ServiceRegistryFile


reportApplied(file): void

Provider: report what is actually applied.

Parameter Type
file AppliedFile

void


routesPath(provider): string

Parameter Type
provider string

string


serviceAddress(key, path?): string

Where a service listens, e.g. http://127.0.0.1:4885. Throws when it is unknown or serves nothing.

Parameter Type
key string
path? string

string


serviceEntry(key, path?): ServiceEntry

One service’s entry. Throws when the registry does not list it.

Parameter Type
key string
path? string

ServiceEntry


serviceKey(bag, service): string

<bag>.<service>, the name every client looks up.

Parameter Type
bag string
service string

string


serviceRegistryPath(): string

<app support>/bag-resources.json. BARRY_SERVICE_REGISTRY redirects it for one test.

string


setInstanceEnvValue(key, value, path?): void

Set one key, keeping every other line (comments included) as it was.

Written through a temp file and a rename, at mode 0600, so a crash never leaves half a secrets file and no other user can read it.

Parameter Type
key string
value string
path string

void


stableNodePath(): string

The Node installed files name: a release current runs its own runtime and a linked one the BARRY_NODE its wrappers carry, whatever Node runs this process; without current, the running Node.

string


useTestInstance(services?): string

Point BARRY_HOME at a new instance whose registry lists the core services plus services (registry key to URL), and return its root.

Parameter Type
services Record<string, string>

string


validateEnv(options?): EnvValidationResult

Validate that every required env var is set. Call at service startup for fail-fast behavior.

Parameter Type
options? { service?: BarryService; }
options.service? BarryService

EnvValidationResult

ValidationResult naming what is missing


writePrivateFile(path, contents): void

Write a generated config in a caller-owned directory, private on every reuse.

Parameter Type
path string
contents string

void


writeServiceRegistry(file, path?): void

Replace the registry in one step: write a temp file, then rename over.

A reader never sees half a file, because every client reads this on every call and a torn read would look like an empty instance.

Parameter Type
file ServiceRegistryFile
path string

void