Skip to content

Commit 0320eca

Browse files
authored
feat(open): prefer OAuth alias URLs
## Summary - make OAuth alias hosts the automatic browser-facing default when OAuth is enabled - add project-level `open.prefer` and one-shot `hack open --prefer <auto|alias|dev>` controls - apply the preference consistently to service shorthand, linked-worktree branch URLs, and `hack branch open` - preserve explicit URLs and fully qualified hostnames exactly as entered - update generated config/schema, CLI reference, docs, and agent guidance ## Why Projects that enable OAuth need browser-facing `.hack.gy` aliases for callbacks and shared cookie domains, while `dev_host` should remain the stable primary routing identity. Previously `hack open` always returned the primary `.hack` host, forcing applications and agents to reconstruct or redirect to the alias themselves. ## User impact With the default `open.prefer: auto`, `hack open` now opens the alias whenever `oauth.enabled` is true and falls back to the dev host otherwise. Users can pin either behavior in project config or override one invocation. Container-to-container traffic remains on Compose DNS. ## Validation - `bun run check` - `bunx tsc -p packages/cli/tsconfig.json --noEmit` - `bun run build` - focused unit/documentation tests: 34 passed - `bun tests/e2e/run.ts --only=worktree-branch-default` - full unit suite: 915 passed, 5 skipped; the sole failure is the existing sandbox-only `ps` EPERM in `daemon-command.test.ts` - full local E2E: 8 scenarios passed; lifecycle process-table scenario is likewise sandbox-blocked by `ps` ## Release signal Feature change; publish as a minor release.
1 parent 4b76a15 commit 0320eca

21 files changed

Lines changed: 608 additions & 47 deletions

.codex/skills/hack-cli/SKILL.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ Use `hack` as the primary interface for local-first development.
1212

1313
## Integration freshness
1414

15-
- These instructions were generated by hack CLI v3.3.6; treat cached rules from another version as potentially stale.
15+
- These instructions were generated by hack CLI v3.4.1; treat cached rules from another version as potentially stale.
1616
- At session start, audit project and global integrations with `hack setup sync --all-scopes --check`.
1717
- If anything is stale, missing, or deprecated, run `hack setup sync --all-scopes`, then reload the agent session so cached instructions are replaced.
1818
- Never copy or hand-edit generated Hack rules to refresh them; update the CLI and run the sync command.
19-
- Content revision: `64098e5ae1ea` (version alone is not a freshness guarantee).
19+
- Content revision: `902b04fe1469` (version alone is not a freshness guarantee).
2020

2121
## Product boundary
2222

@@ -52,6 +52,7 @@ Use `hack` as the primary interface for local-first development.
5252
- Primary host comes from `dev_host` (default: `<project>.hack`).
5353
- Subdomain pattern is `<sub>.<dev_host>` (for example: `api.myapp.hack`).
5454
- OAuth alias (when enabled) also routes `<dev_host>.<tld>` and `<sub>.<dev_host>.<tld>` (default tld: `gy`).
55+
- Browser launches automatically prefer a routed OAuth alias when enabled; custom development hosts outside `.hack` stay on the primary host. Set `open.prefer` or pass `hack open --prefer <auto|alias|dev>` to override.
5556
- Not every compose service is routable: only services with Caddy labels and on `hack-dev` are exposed.
5657
- Required labels for HTTP services: `caddy`, `caddy.reverse_proxy`, `caddy.tls=internal`.
5758
- Quick checks: `hack open`, `hack open <sub>`, `hack open --json`.
@@ -70,7 +71,7 @@ Use `hack` as the primary interface for local-first development.
7071
- Source-of-truth files: `.hack/docker-compose.yml`, `.hack/hack.config.json`, `.hack/hack.env.default.yaml`, and optional `.hack/hack.env.<overlay>.yaml`.
7172
- Worktree-local env override files: `.hack/hack.env.local.yaml` and `.hack/hack.env.<overlay>.local.yaml`.
7273
- Local-only files: `.hack.secret.key`, optional `.hack/.env` compatibility output, `.hack/.env.state.json`, and `.hack/.internal/` (runtime/local machine state; keep gitignored).
73-
- Generated (do not hand-edit): `.hack/.internal/compose.override.yml`, `.hack/.internal/compose.env.override.yml`, `.hack/.branch/compose.<branch>.override.yml`.
74+
- Generated (do not hand-edit): `.hack/.internal/compose.override.yml`, `.hack/.internal/compose.env.override.yml`, `.hack/.internal/compose.runtime.override.yml`, `.hack/.branch/compose.<branch>.override.yml`, `.hack/.branch/compose.<branch>.runtime.override.yml`.
7475
- Managed via CLI: `.hack/.internal/extra-hosts.json` (use `hack internal extra-hosts ...` commands).
7576
- Lifecycle runtime files: `.hack/.internal/lifecycle/state.json`, `.hack/.internal/lifecycle/*.log`.
7677
- Ignore rules: hack owns a committed `.hack/.gitignore` (self-healing on init/up) covering machine-local generated files (`.internal/`, `.branch/`, `.env`, `.env.state.json`, `hack.env*.local.yaml`); keep it committed, and if generated files leaked into git, `hack doctor --fix` untracks them (files stay on disk).
@@ -104,7 +105,7 @@ Use `hack` as the primary interface for local-first development.
104105
- Command inside an already-running service container: `hack exec <service> -- <cmd...>`.
105106
- Host script that needs hack-stored env: `hack host exec --env <overlay> --scope <service> -- <cmd...>` — this is THE way to run repo scripts; never read .env files directly.
106107
- Interactive host shell with injected env: `hack host shell --env <overlay> --scope <service>`.
107-
- Call a service over HTTP (from the host or between containers): use its Caddy hostname `https://<sub>.<dev_host>`; discover routable URLs with `hack open --json`.
108+
- Browser/host URL: use `hack open <service> --json` (OAuth aliases are preferred when enabled). Container-to-container traffic should use Compose DNS.
108109

109110
## Logs (default is compose)
110111

.cursor/rules/hack.mdc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ Prefer `hack` when shell access is available. Use MCP only when shell access is
77

88
## Integration freshness
99

10-
- These instructions were generated by hack CLI v3.3.6; treat cached rules from another version as potentially stale.
10+
- These instructions were generated by hack CLI v3.4.1; treat cached rules from another version as potentially stale.
1111
- At session start, audit project and global integrations with `hack setup sync --all-scopes --check`.
1212
- If anything is stale, missing, or deprecated, run `hack setup sync --all-scopes`, then reload the agent session so cached instructions are replaced.
1313
- Never copy or hand-edit generated Hack rules to refresh them; update the CLI and run the sync command.
14-
- Content revision: `64098e5ae1ea` (version alone is not a freshness guarantee).
14+
- Content revision: `902b04fe1469` (version alone is not a freshness guarantee).
1515

1616
## Product boundary
1717

@@ -34,7 +34,7 @@ Prefer `hack` when shell access is available. Use MCP only when shell access is
3434
- Source-of-truth files: `.hack/docker-compose.yml`, `.hack/hack.config.json`, `.hack/hack.env.default.yaml`, and optional `.hack/hack.env.<overlay>.yaml`.
3535
- Worktree-local env override files: `.hack/hack.env.local.yaml` and `.hack/hack.env.<overlay>.local.yaml`.
3636
- Local-only files: `.hack.secret.key`, optional `.hack/.env` compatibility output, `.hack/.env.state.json`, and `.hack/.internal/` (runtime/local machine state; keep gitignored).
37-
- Generated (do not hand-edit): `.hack/.internal/compose.override.yml`, `.hack/.internal/compose.env.override.yml`, `.hack/.branch/compose.<branch>.override.yml`.
37+
- Generated (do not hand-edit): `.hack/.internal/compose.override.yml`, `.hack/.internal/compose.env.override.yml`, `.hack/.internal/compose.runtime.override.yml`, `.hack/.branch/compose.<branch>.override.yml`, `.hack/.branch/compose.<branch>.runtime.override.yml`.
3838
- Managed via CLI: `.hack/.internal/extra-hosts.json` (use `hack internal extra-hosts ...` commands).
3939
- Lifecycle runtime files: `.hack/.internal/lifecycle/state.json`, `.hack/.internal/lifecycle/*.log`.
4040
- Ignore rules: hack owns a committed `.hack/.gitignore` (self-healing on init/up) covering machine-local generated files (`.internal/`, `.branch/`, `.env`, `.env.state.json`, `hack.env*.local.yaml`); keep it committed, and if generated files leaked into git, `hack doctor --fix` untracks them (files stay on disk).
@@ -61,7 +61,7 @@ Prefer `hack` when shell access is available. Use MCP only when shell access is
6161
- Command inside an already-running service container: `hack exec <service> -- <cmd...>`.
6262
- Host script that needs hack-stored env: `hack host exec --env <overlay> --scope <service> -- <cmd...>` — this is THE way to run repo scripts; never read .env files directly.
6363
- Interactive host shell with injected env: `hack host shell --env <overlay> --scope <service>`.
64-
- Call a service over HTTP (from the host or between containers): use its Caddy hostname `https://<sub>.<dev_host>`; discover routable URLs with `hack open --json`.
64+
- Browser/host URL: use `hack open <service> --json` (OAuth aliases are preferred when enabled). Container-to-container traffic should use Compose DNS.
6565

6666
## Lifecycle + startup
6767

AGENTS.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,11 @@ Most formatting and common issues are automatically fixed by Biome. Run `bun x u
210210
Use `hack` as the single interface for local-first runtime orchestration (compose, DNS/TLS, logs, env, and persistent project workspaces).
211211

212212
Integration freshness:
213-
- These instructions were generated by hack CLI v3.3.6; treat cached rules from another version as potentially stale.
213+
- These instructions were generated by hack CLI v3.4.1; treat cached rules from another version as potentially stale.
214214
- At session start, audit project and global integrations with `hack setup sync --all-scopes --check`.
215215
- If anything is stale, missing, or deprecated, run `hack setup sync --all-scopes`, then reload the agent session so cached instructions are replaced.
216216
- Never copy or hand-edit generated Hack rules to refresh them; update the CLI and run the sync command.
217-
- Content revision: `64098e5ae1ea` (version alone is not a freshness guarantee).
217+
- Content revision: `902b04fe1469` (version alone is not a freshness guarantee).
218218

219219
Product boundary:
220220
- Supported v3 surface: project init, up/down/restart, open, logs, env, host exec/shell, sessions, doctor, and daemon.
@@ -245,6 +245,7 @@ Hostname routing + Caddy labels:
245245
- Primary host comes from `dev_host` (default: `<project>.hack`).
246246
- Subdomain pattern is `<sub>.<dev_host>` (for example: `api.myapp.hack`).
247247
- OAuth alias (when enabled) also routes `<dev_host>.<tld>` and `<sub>.<dev_host>.<tld>` (default tld: `gy`).
248+
- Browser launches automatically prefer a routed OAuth alias when enabled; custom development hosts outside `.hack` stay on the primary host. Set `open.prefer` or pass `hack open --prefer <auto|alias|dev>` to override.
248249
- Not every compose service is routable: only services with Caddy labels and on `hack-dev` are exposed.
249250
- Required labels for HTTP services: `caddy`, `caddy.reverse_proxy`, `caddy.tls=internal`.
250251
- Quick checks: `hack open`, `hack open <sub>`, `hack open --json`.
@@ -261,7 +262,7 @@ Project files (managed vs generated):
261262
- Source-of-truth files: `.hack/docker-compose.yml`, `.hack/hack.config.json`, `.hack/hack.env.default.yaml`, and optional `.hack/hack.env.<overlay>.yaml`.
262263
- Worktree-local env override files: `.hack/hack.env.local.yaml` and `.hack/hack.env.<overlay>.local.yaml`.
263264
- Local-only files: `.hack.secret.key`, optional `.hack/.env` compatibility output, `.hack/.env.state.json`, and `.hack/.internal/` (runtime/local machine state; keep gitignored).
264-
- Generated (do not hand-edit): `.hack/.internal/compose.override.yml`, `.hack/.internal/compose.env.override.yml`, `.hack/.branch/compose.<branch>.override.yml`.
265+
- Generated (do not hand-edit): `.hack/.internal/compose.override.yml`, `.hack/.internal/compose.env.override.yml`, `.hack/.internal/compose.runtime.override.yml`, `.hack/.branch/compose.<branch>.override.yml`, `.hack/.branch/compose.<branch>.runtime.override.yml`.
265266
- Managed via CLI: `.hack/.internal/extra-hosts.json` (use `hack internal extra-hosts ...` commands).
266267
- Lifecycle runtime files: `.hack/.internal/lifecycle/state.json`, `.hack/.internal/lifecycle/*.log`.
267268
- Ignore rules: hack owns a committed `.hack/.gitignore` (self-healing on init/up) covering machine-local generated files (`.internal/`, `.branch/`, `.env`, `.env.state.json`, `hack.env*.local.yaml`); keep it committed, and if generated files leaked into git, `hack doctor --fix` untracks them (files stay on disk).
@@ -291,7 +292,7 @@ Running things (decision guide):
291292
- Command inside an already-running service container: `hack exec <service> -- <cmd...>`.
292293
- Host script that needs hack-stored env: `hack host exec --env <overlay> --scope <service> -- <cmd...>` — this is THE way to run repo scripts; never read .env files directly.
293294
- Interactive host shell with injected env: `hack host shell --env <overlay> --scope <service>`.
294-
- Call a service over HTTP (from the host or between containers): use its Caddy hostname `https://<sub>.<dev_host>`; discover routable URLs with `hack open --json`.
295+
- Browser/host URL: use `hack open <service> --json` (OAuth aliases are preferred when enabled). Container-to-container traffic should use Compose DNS.
295296

296297
Logs (default is compose):
297298
- Fast tail: `hack logs --pretty`

CLAUDE.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ This project uses Obsidian for project context, specs, research, and progress tr
8080
Use `hack` as the single interface for local-first runtime orchestration (compose, DNS/TLS, logs, env, and persistent project workspaces).
8181

8282
Integration freshness:
83-
- These instructions were generated by hack CLI v3.3.6; treat cached rules from another version as potentially stale.
83+
- These instructions were generated by hack CLI v3.4.1; treat cached rules from another version as potentially stale.
8484
- At session start, audit project and global integrations with `hack setup sync --all-scopes --check`.
8585
- If anything is stale, missing, or deprecated, run `hack setup sync --all-scopes`, then reload the agent session so cached instructions are replaced.
8686
- Never copy or hand-edit generated Hack rules to refresh them; update the CLI and run the sync command.
87-
- Content revision: `64098e5ae1ea` (version alone is not a freshness guarantee).
87+
- Content revision: `902b04fe1469` (version alone is not a freshness guarantee).
8888

8989
Product boundary:
9090
- Supported v3 surface: project init, up/down/restart, open, logs, env, host exec/shell, sessions, doctor, and daemon.
@@ -115,6 +115,7 @@ Hostname routing + Caddy labels:
115115
- Primary host comes from `dev_host` (default: `<project>.hack`).
116116
- Subdomain pattern is `<sub>.<dev_host>` (for example: `api.myapp.hack`).
117117
- OAuth alias (when enabled) also routes `<dev_host>.<tld>` and `<sub>.<dev_host>.<tld>` (default tld: `gy`).
118+
- Browser launches automatically prefer a routed OAuth alias when enabled; custom development hosts outside `.hack` stay on the primary host. Set `open.prefer` or pass `hack open --prefer <auto|alias|dev>` to override.
118119
- Not every compose service is routable: only services with Caddy labels and on `hack-dev` are exposed.
119120
- Required labels for HTTP services: `caddy`, `caddy.reverse_proxy`, `caddy.tls=internal`.
120121
- Quick checks: `hack open`, `hack open <sub>`, `hack open --json`.
@@ -131,7 +132,7 @@ Project files (managed vs generated):
131132
- Source-of-truth files: `.hack/docker-compose.yml`, `.hack/hack.config.json`, `.hack/hack.env.default.yaml`, and optional `.hack/hack.env.<overlay>.yaml`.
132133
- Worktree-local env override files: `.hack/hack.env.local.yaml` and `.hack/hack.env.<overlay>.local.yaml`.
133134
- Local-only files: `.hack.secret.key`, optional `.hack/.env` compatibility output, `.hack/.env.state.json`, and `.hack/.internal/` (runtime/local machine state; keep gitignored).
134-
- Generated (do not hand-edit): `.hack/.internal/compose.override.yml`, `.hack/.internal/compose.env.override.yml`, `.hack/.branch/compose.<branch>.override.yml`.
135+
- Generated (do not hand-edit): `.hack/.internal/compose.override.yml`, `.hack/.internal/compose.env.override.yml`, `.hack/.internal/compose.runtime.override.yml`, `.hack/.branch/compose.<branch>.override.yml`, `.hack/.branch/compose.<branch>.runtime.override.yml`.
135136
- Managed via CLI: `.hack/.internal/extra-hosts.json` (use `hack internal extra-hosts ...` commands).
136137
- Lifecycle runtime files: `.hack/.internal/lifecycle/state.json`, `.hack/.internal/lifecycle/*.log`.
137138
- Ignore rules: hack owns a committed `.hack/.gitignore` (self-healing on init/up) covering machine-local generated files (`.internal/`, `.branch/`, `.env`, `.env.state.json`, `hack.env*.local.yaml`); keep it committed, and if generated files leaked into git, `hack doctor --fix` untracks them (files stay on disk).
@@ -161,7 +162,7 @@ Running things (decision guide):
161162
- Command inside an already-running service container: `hack exec <service> -- <cmd...>`.
162163
- Host script that needs hack-stored env: `hack host exec --env <overlay> --scope <service> -- <cmd...>` — this is THE way to run repo scripts; never read .env files directly.
163164
- Interactive host shell with injected env: `hack host shell --env <overlay> --scope <service>`.
164-
- Call a service over HTTP (from the host or between containers): use its Caddy hostname `https://<sub>.<dev_host>`; discover routable URLs with `hack open --json`.
165+
- Browser/host URL: use `hack open <service> --json` (OAuth aliases are preferred when enabled). Container-to-container traffic should use Compose DNS.
165166

166167
Logs (default is compose):
167168
- Fast tail: `hack logs --pretty`

docs/architecture.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ graph LR
6262

6363
- Project scope (`.hack`)
6464
- `docker-compose.yml` defines services + Caddy labels
65-
- `hack.config.json` stores project name, dev host, log preferences, OAuth alias
65+
- `hack.config.json` stores project name, dev host, log preferences, OAuth alias, and browser
66+
launch preference (`open.prefer`)
6667
- `controlPlane.gateway.enabled` marks the project as gateway-capable
6768
- Optional overrides:
6869
- `.internal/compose.override.yml` (generated internal DNS/TLS injection)
@@ -321,9 +322,11 @@ one, or set `worktree.auto_branch=false` to opt into the base instance explicitl
321322
- `.env` (optional, only when explicitly materialized)
322323
- `.internal/compose.override.yml`
323324
- `.internal/compose.env.override.yml`
325+
- `.internal/compose.runtime.override.yml`
324326
- `.internal/extra-hosts.json`
325327
- `.internal/lifecycle/state.json` and `.internal/lifecycle/*.log`
326328
- `.branch/compose.<branch>.override.yml`
329+
- `.branch/compose.<branch>.runtime.override.yml`
327330

328331
## Key design choices
329332

0 commit comments

Comments
 (0)