Skip to main content

localhost-apps

Add, remove, or list permanent Caddy-based named localhost apps backed by macOS LaunchAgents. Use for always-on local servers, *.localhost proxies, Caddy routes, or launchd-managed development apps on this machine.

Informações da origem

Repositório
PaulRBerg/dotfiles
Última atividade na origem
19 de setembro de 2026 às 10:04
Idioma detectado do SKILL.md
inglês
Estrelas
2
Forks
1

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
3 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
argument-hint
<list|add|remove> [app-name]
compatibility
Requires macOS, chezmoi, Caddy, launchd, Bun, and this dotfiles repository.
name
localhost-apps
description
Add, remove, or list permanent Caddy-based named localhost apps backed by macOS LaunchAgents. Use for always-on local servers, *.localhost proxies, Caddy routes, or launchd-managed development apps on this machine.
# Permanent Localhost Apps Manage named HTTPS localhost proxies and the macOS LaunchAgents that keep their upstream apps running. ## Arguments - `list` or no arguments: Show every permanent localhost app and its live health. - `add <app-name>`: Add `<app-name>.localhost`, its upstream port, and its always-on service. - `remove <app-name>`: Remove the proxy and service after explicit confirmation. Use an explicit user-supplied hostname, port, label, source path, or command when provided. Otherwise derive them from repository evidence and the conventions below. ## Invariants - A permanent app has both a Caddy route in `dot_config/caddy/Caddyfile` and a matching `KeepAlive` LaunchAgent under `Library/LaunchAgents/`. - Bind app servers to `127.0.0.1`; expose them through `https://<name>.localhost`, never a LAN interface. - Treat proxy compatibility as an application invariant: its framework, server, API, same-origin, CSRF, and host checks must accept the exact named HTTPS origin without broadening trust to arbitrary `.localhost` hosts or forwarded headers. - Give every service a distinct label, port, working directory, and log under `~/Library/Logs/`. - Keep the app repository and its data intact when removing a proxy unless the user separately asks to delete them. - Follow the coordination, validation, commit, push, and scoped-apply rules in `AGENTS.md` for every affected repository. - Treat `list` as read-only. Adding writes repository and live launchd state. Removing is destructive and requires confirmation after the exact removal set is known. ## List Run: ```sh bun run .agents/skills/localhost-apps/scripts/list.ts ``` Relay its Markdown table without restating healthy rows. Investigate any missing metadata, unloaded service, failed listener, or non-successful HTTPS response before claiming the inventory is healthy. ### Helper interface `scripts/list.ts` accepts no arguments. Run it with `bun run .agents/skills/localhost-apps/scripts/list.ts` from the repository. It reads the Caddyfile and matching plist templates, queries launchd, probes HTTPS, prints a Markdown table to stdout, and exits nonzero only when repository metadata cannot be read or parsed. An unhealthy service remains a successful inventory result and is marked in the table. ## Add 1. Inspect the app repository's instructions, manifest, launch command, bind address, existing port, and durable docs. Inspect the nearest analogous Caddy block, LaunchAgent plist, and reload hook in this repository. 2. Resolve the hostname, source directory, launch command, service label, log path, and port. Preserve a safe existing port unless the user requested a change; otherwise choose a random free port in `8000-8999` that is absent from the Caddyfile, the app repository, and `lsof -nP -iTCP -sTCP:LISTEN`. 3. Identify every write target, then acquire exact `ai-coord` scopes in each Git repository before editing. A normal add changes: - the app's bind/port configuration and its AGENTS/README guidance; - `dot_config/caddy/Caddyfile`; - `Library/LaunchAgents/<label>.plist.tmpl`; - `dot_setup/run_onchange_after_setup_<slug>_macos.sh.tmpl`; - this repository's local-HTTPS guidance in `AGENTS.md`. 4. Configure the app to bind strictly to `127.0.0.1:<port>`. Preserve its established development or production command; do not invent a build/deployment layer merely to daemonize it. 5. Trace every framework allowlist and server-side `Host`, `Origin`, same-origin, or CSRF check used by browser and API requests. Where enforcement exists, allow exactly `<name>.localhost` and its default-TLS form `<name>.localhost:443`, with expected origin `https://<name>.localhost`; retain required direct-loopback access. Never authorize wildcard `.localhost` subdomains, attacker suffixes, non-default ports, or `X-Forwarded-*` headers. 6. Add a Caddy block with comments naming the app, source directory, and LaunchAgent. Proxy to `127.0.0.1:<port>`. 7. Add a plist following the closest existing service. Include `KeepAlive`, `RunAtLoad`, `ProcessType`, `WorkingDirectory`, explicit program arguments, stdout/stderr log paths, and only the PATH entries the command needs. 8. Add a `run_onchange_after_setup_*_macos.sh.tmpl` hook following an existing reload hook. Include the plist's hash so changes retrigger it; validate the rendered plist, boot out an old instance, bootstrap with the established retry, and prove launchd loaded the label. 9. Update durable instructions so users and agents open the named HTTPS URL and do not start a competing server on the default port. Document the service label, log, and restart command. 10. Add proxy regression coverage for the real browser path. For an app with an API, test a read and a representative state-changing request using the named `Host` and exact HTTPS `Origin`, plus rejection of sibling hosts, attacker suffixes, wrong schemes/ports, and forwarded-header impersonation. A successful HTML shell response is not proof that the proxied app works. 11. Run the narrow app checks plus this repository's `just full-check`, `caddy validate`, and `gitleaks git --redact --no-banner --no-color`. Format only owned files. 12. Commit and push each coherent repository change under its local rules. Authenticate 1Password, apply chezmoi using the repository's changed-file count rule, and include Caddy's hash-triggered hook whenever the Caddyfile changed. 13. Verify the LaunchAgent is running and the chosen port is listening. Exercise the named HTTPS page and its critical proxied API read/write flow without a manually started process; do not stop at `curl` of `/`. Check the system keychain for `Caddy Local Authority`; if absent, tell the user to run `caddy trust` rather than invoking its sudo prompt yourself. ## Remove 1. Run the inventory and resolve the exact Caddy block, service label, plist source, reload hook, installed plist, documentation references, listener, and app repository. State that the app repository and data will remain. 2. Ask for confirmation to unload the service and delete the managed proxy/service files. Do not mutate state before confirmation. 3. After confirmation, acquire exact `ai-coord` scopes. Boot out `gui/$(id -u)/<label>`, remove the Caddy block, source plist, and reload hook, and update durable docs. 4. Add `Library/LaunchAgents/<label>.plist` to `.chezmoiremove` with a concise reason. This is required so other machines delete the formerly managed target after pulling the source deletion; deleting only the source leaves an orphan. 5. Leave the app's repository, data, dependencies, and port configuration unchanged unless the user explicitly expands scope. Remove only instructions that falsely claim the permanent service still exists. 6. Validate the remaining Caddyfile, plist/templates, shell, docs, and repository checks; commit and push coherent changes; then authenticate and apply chezmoi. 7. Verify launchd no longer knows the label, the old port has no listener from that service, the removed hostname is no longer routed, and the inventory table no longer contains the app. ## Completion - For `list`, return the helper's table and only the evidence needed to explain unhealthy rows. - For `add` or `remove`, lead with the resulting URL/service state, then report the label, port, source, log, validation, pushed commits, apply result, and whether the user must run `caddy trust`.
Ver no GitHub