Skip to content
Hallway is out (npm i -g hallway): v0, v1 and v2 have shipped, apart from checking it all on a real Mac. See the roadmap.

apps/<slug>.yaml

Each declared app is one file, ~/.hallway/apps/<slug>.yaml. The filename is the slug.

The slug becomes a hostname label in fronted mode, so it must be a valid DNS label: lowercase letters, digits and hyphens, starting and ending with a letter or digit, at most 63 characters (^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$). The dashboard’s own label (hallway by default), www and api are reserved.

name: Slides
port: 4321
name: Slides
description: Quarterly review deck
port: 4321 # REQUIRED. The port the app actually listens on. Never auto-changed.
host: 127.0.0.1 # the upstream host; default 127.0.0.1
expected: running # running | stopped | adhoc
# running: should always be up; not responding = "down"
# stopped: intentionally off; shown calmly as "stopped"
# adhoc: up sometimes; not responding = "stopped", not "down"
health: # optional; without it, Hallway probes GET /
path: /api/health
expectStatus: 200 # optional; default: any 2xx when path is given
proxy: # fronted mode only
preserveHost: false # default false: Host is rewritten to the upstream
aliases: [] # extra hostnames, e.g. [deck] → deck.<base>
service: # optional. Present = Hallway keeps it alive (launchd / systemd).
command: ["npx", "astro", "dev", "--port", "4321"] # an argv array, resolved to absolute paths
cwd: ~/Code/slides
env: {} # PORT and HOST are set automatically
runAtLoad: true
keepAlive: true
links: # optional deep links shown on the card
- { label: Speaker notes, path: /notes }
project: # optional; filled in automatically when claimed
dir: ~/Code/slides
repo: https://github.com/example/slides
tags: [decks]
icon: auto # auto (favicon) | an emoji | a path to an image in the data home | a URL
FieldRequiredMeaning
nameDisplay name.
descriptionOne line, shown in the detail drawer.
portYesThe port the app listens on. Hallway never changes it.
hostThe upstream host, default 127.0.0.1.
expectedrunning, stopped or adhoc: decides whether “not listening” is down or stopped. See Health states.
health.pathProbe this path instead of /.
health.expectStatusThe status that means healthy; default any 2xx.
proxy.preserveHostPass the browser’s Host through instead of rewriting it. See Host-header rewriting. v1
proxy.aliasesExtra hostname labels for the app: [deck] also serves it at deck.<base>. v1
serviceMakes the app a managed service. Write it with hallway run or hallway service add rather than by hand. v1
service.commandWith serviceThe command as an argv array, not a shell string.
service.cwdWorking directory.
service.envExtra environment variables. PORT, HOST and HOSTNAME are set for you.
service.runAtLoad, service.keepAliveStart at login; restart if it exits.
linksDeep links on the card: a label, and either a path on the app or a full url.
project.dir, project.repoWhere the code lives.
tagsFree-form tags, for filtering.
iconauto uses the app’s favicon.

Hallway validates before it writes (rejecting bad slugs, ports outside 1–65535 and unknown values) and validates what it reads. Two declared apps on the same port is a warning, not an error, because one of them may be stopped.

A file that fails to parse or validate keeps its last good version on the dashboard, with the error on its card. Fix the file and the error clears.

Delete it from the dashboard, with hallway app rm, through the API or MCP: the file is moved to backups/removed/, never deleted, so a mistake (yours or an agent’s) is recoverable. Deleting the file yourself works too; the card disappears.