Skip to content

Commit 0b0ec61

Browse files
authored
feat(runtime): expose branch-safe host metadata (#66)
## Summary - inject versioned, non-secret runtime host metadata into every Compose service - expose branch-qualified public route maps plus current-service convenience fields - make `up`, `restart`, targeted restart, `run`, and `exec` inspection consume consistent generated Compose overrides - extract and directly test branch-host rewriting - document Compose-DNS vs public-URL usage and bump agent-integration freshness ## Runtime contract Containers receive `HACK_RUNTIME_METADATA`, `HACK_DEV_URL`, `HACK_ALIAS_URL`, `HACK_SERVICE_NAME`, `HACK_SERVICE_URL`, and `HACK_SERVICE_URLS`. The versioned JSON document includes all routable services, avoiding lossy service-name-to-env-key conversion. Explicit project env values retain precedence for backward compatibility. ## Verification - `bun test` — 897 pass, 5 skip, 0 fail - focused metadata/branch/run/exec/agent tests — 27 pass, 0 fail - `bun run check` - `bun run typecheck` - `bun run build` - Docker E2E `worktree-parallel-up` — primary and branch containers expose distinct URLs; metadata survives restart ## Release decision This is a user-facing runtime capability and should produce a feature/minor release signal. The Conventional Commit title intentionally uses `feat(runtime)`. ## Landing order PR #65 should land first; then this branch should be updated from `main` before merge so its `project.ts` changes include the completion-gate fixes.
1 parent 07506ff commit 0b0ec61

15 files changed

Lines changed: 913 additions & 144 deletions

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Use `hack` as the primary interface for local-first development.
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: `eef2b0142b95` (version alone is not a freshness guarantee).
19+
- Content revision: `64098e5ae1ea` (version alone is not a freshness guarantee).
2020

2121
## Product boundary
2222

@@ -154,6 +154,7 @@ Use `hack` as the primary interface for local-first development.
154154
- Use a branch instance when you need two versions running at once (PR review, experiments, migrations) or want to keep a stable environment while testing another branch.
155155
- Target one with `--branch <name>` on up/open/logs/down (for example: `hack up --branch <name> --detach`).
156156
- Linked worktrees pick a branch instance automatically (see Linked git worktrees).
157+
- Containers receive `HACK_RUNTIME_METADATA` plus `HACK_DEV_URL`, `HACK_ALIAS_URL`, and current-service URL fields derived from effective Caddy routes. Use Compose DNS for internal traffic and this metadata for browser-facing links, OAuth callbacks, and webhooks.
157158

158159
## Run commands inside services
159160

.cursor/rules/hack.mdc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Prefer `hack` when shell access is available. Use MCP only when shell access is
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: `eef2b0142b95` (version alone is not a freshness guarantee).
14+
- Content revision: `64098e5ae1ea` (version alone is not a freshness guarantee).
1515

1616
## Product boundary
1717

AGENTS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ Integration freshness:
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: `eef2b0142b95` (version alone is not a freshness guarantee).
217+
- Content revision: `64098e5ae1ea` (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.
@@ -336,6 +336,7 @@ Branch instances (parallel envs):
336336
- Use a branch instance when you need two versions running at once (PR review, experiments, migrations) or want to keep a stable environment while testing another branch.
337337
- Target one with `--branch <name>` on up/open/logs/down (for example: `hack up --branch <name> --detach`).
338338
- Linked worktrees pick a branch instance automatically (see Linked git worktrees).
339+
- Containers receive `HACK_RUNTIME_METADATA` plus `HACK_DEV_URL`, `HACK_ALIAS_URL`, and current-service URL fields derived from effective Caddy routes. Use Compose DNS for internal traffic and this metadata for browser-facing links, OAuth callbacks, and webhooks.
339340

340341
Run commands inside services:
341342
- One-off: `hack run <service> <cmd...>` (uses `docker compose run --rm`)

CLAUDE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Integration freshness:
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: `eef2b0142b95` (version alone is not a freshness guarantee).
87+
- Content revision: `64098e5ae1ea` (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.
@@ -206,6 +206,7 @@ Branch instances (parallel envs):
206206
- Use a branch instance when you need two versions running at once (PR review, experiments, migrations) or want to keep a stable environment while testing another branch.
207207
- Target one with `--branch <name>` on up/open/logs/down (for example: `hack up --branch <name> --detach`).
208208
- Linked worktrees pick a branch instance automatically (see Linked git worktrees).
209+
- Containers receive `HACK_RUNTIME_METADATA` plus `HACK_DEV_URL`, `HACK_ALIAS_URL`, and current-service URL fields derived from effective Caddy routes. Use Compose DNS for internal traffic and this metadata for browser-facing links, OAuth callbacks, and webhooks.
209210

210211
Run commands inside services:
211212
- One-off: `hack run <service> <cmd...>` (uses `docker compose run --rm`)

docs/cli.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,52 @@ Opt out:
158158

159159
The primary checkout is unchanged: no `--branch` means the base instance.
160160

161+
### Runtime host metadata
162+
163+
Containers started by `hack up`, `hack restart`, and `hack run` receive the effective instance and
164+
public-route metadata. This keeps server-generated links, OAuth callbacks, webhooks, and other
165+
browser-facing URLs isolated when the same project runs in multiple worktrees.
166+
167+
| Variable | Value |
168+
| --- | --- |
169+
| `HACK_BRANCH` | Effective branch slug, or an empty string for the base instance |
170+
| `HACK_COMPOSE_PROJECT` | Effective Compose project name |
171+
| `HACK_DEV_HOST` / `HACK_DEV_URL` | Effective root development host and HTTPS URL |
172+
| `HACK_ALIAS_HOST` / `HACK_ALIAS_URL` | Effective OAuth alias host and URL, when enabled |
173+
| `HACK_SERVICE_NAME` | Current Compose service name |
174+
| `HACK_SERVICE_URL` | Current service's first public URL, when routable |
175+
| `HACK_SERVICE_URLS` | JSON array of every public URL for the current service |
176+
| `HACK_RUNTIME_METADATA` | Versioned JSON document containing the instance hosts and every routable service's URL list |
177+
178+
Example `HACK_RUNTIME_METADATA` for a branch instance:
179+
180+
```json
181+
{
182+
"version": 1,
183+
"branch": "feature-x",
184+
"composeProject": "demo--feature-x",
185+
"hosts": {
186+
"dev": "feature-x.demo.hack",
187+
"alias": "feature-x.demo.hack.gy"
188+
},
189+
"services": {
190+
"web": {
191+
"urls": ["https://feature-x.demo.hack"]
192+
},
193+
"api": {
194+
"urls": ["https://api.feature-x.demo.hack"]
195+
}
196+
}
197+
}
198+
```
199+
200+
The service map is derived from effective Caddy routes; unroutable services are omitted. Use
201+
Compose DNS names such as `http://api:3000` for container-to-container traffic and runtime metadata
202+
only when a public/browser-reachable URL is required. Explicit project env values retain precedence
203+
over generated metadata for backward compatibility. Existing containers receive the contract after
204+
their next `hack up` or `hack restart`; `hack exec` observes the values already stored in the running
205+
container.
206+
161207
Linked worktrees also inherit the project secret key automatically from the primary checkout
162208
through the shared git common dir, so you don't need to copy `.hack.secret.key` by hand. Set
163209
`HACK_ENV_SECRET_KEY` for CI or fully detached environments. `hack doctor` flags divergent secret

src/agents/instruction-source.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ export const INSTRUCTION_SECTIONS: readonly InstructionSection[] = [
247247
"Use a branch instance when you need two versions running at once (PR review, experiments, migrations) or want to keep a stable environment while testing another branch.",
248248
"Target one with `--branch <name>` on up/open/logs/down (for example: `hack up --branch <name> --detach`).",
249249
"Linked worktrees pick a branch instance automatically (see Linked git worktrees).",
250+
"Containers receive `HACK_RUNTIME_METADATA` plus `HACK_DEV_URL`, `HACK_ALIAS_URL`, and current-service URL fields derived from effective Caddy routes. Use Compose DNS for internal traffic and this metadata for browser-facing links, OAuth callbacks, and webhooks.",
250251
],
251252
},
252253
{

src/agents/integration-revision.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
* source test recomputes this value and fails whenever guidance changes
44
* without a revision update.
55
*/
6-
export const HACK_AGENT_INTEGRATION_CONTENT_REVISION = "eef2b0142b95";
6+
export const HACK_AGENT_INTEGRATION_CONTENT_REVISION = "64098e5ae1ea";

0 commit comments

Comments
 (0)