Skip to content

feat(init): discovery validation pass + field-report onboarding improvements#58

Merged
roodboi merged 4 commits into
mainfrom
feat/init-discovery-validation
Jul 8, 2026
Merged

feat(init): discovery validation pass + field-report onboarding improvements#58
roodboi merged 4 commits into
mainfrom
feat/init-discovery-validation

Conversation

@roodboi

@roodboi roodboi commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Everything the two field reports (real hack init --with claude runs on a polyglot Vite/Astro/Bun/.NET/Temporal monorepo) taught us about init:

Discovery validation pass (src/init/validation.ts)

  • Cross-package aggregator dedupe: root dev:web-style scripts that delegate to workspace packages no longer produce duplicate services (the field repo's web/web-2) or phantom services (a bun-imaged "backend" that actually ran dotnet)
  • Port-collision detection with deterministic reassignment in --auto mode (field repo: everything on 3000)
  • Non-JS runtime detection (.csproj/go.mod/Cargo.toml/... + script commands incl. --project targets): obviously-wrong placeholder image + TODO comment instead of a silently wrong bun-node guess
  • Backing-service detection (deps + env key names + existing compose): warns about detected-but-unscaffolded postgres/temporal/redis/etc
  • Existing root compose files surfaced as ground-truth pointers
  • Findings emitted as init warnings AND as comments injected into the generated compose (idempotent post-render injection)

Onboarding improvements

  • Partial adoption (backing-services-only) documented as a valid end state in agent-first-setup.md + an explicit Phase 2 decision bullet in the onboarding prompt (the field agent chose this architecture; it was undocumented)
  • Phase 1 env inventory now covers env-in-compose repos (the field repo had zero .env files)
  • Phase 2 now says check for reusable prod images/build contexts before authoring new dev containers (the field agent's over-containerization was only caught by human pushback)
  • Both init paths surface early that full *.hack routing needs hack global install (sudo)

Tests: 12 new validation tests on a polyglot fixture modeled on the field repo; full suite 805/0; e2e green.

🤖 Generated with Claude Code

roodboi and others added 4 commits July 7, 2026 21:10
…ck setup

A real agent-driven onboarding hit a polyglot monorepo where heavy native
toolchains (.NET) and existing host workflows made full containerization the
wrong call, but nothing told the agent that running only backing services
under hack — with app dev servers on the host pointed at routed services —
was a supported, deliberate end state rather than a fallback to fix later.

- docs/guides/agent-first-setup.md: add a "Partial adoption" section covering
  when to choose it, what hack still provides (stable hostnames/TLS, branch
  instances, committed env, lifecycle hooks), how to wire it, and tradeoffs
  vs full containerization.
- src/agents/onboarding-prompt.ts (Phase 2): add a bullet presenting full
  containerization vs backing-services-only as an explicit decision, plus a
  bullet to prefer reusing existing prod Dockerfiles/compose contexts over
  authoring new dev-mode services from scratch.
- src/agents/onboarding-prompt.ts (Phase 1): extend the env-inventory bullet
  so agents also harvest hack env candidates from compose `environment:`
  blocks, Dockerfile `ENV` lines, and CI config when a repo has no `.env*`
  files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Field repos were shipping duplicated services (web/web-2), everything
crammed onto port 3000, silently-wrong bun-node images on non-JS
services, and missing backing-service infra (postgres/temporal) —
all with zero warnings. Add a validation pass (src/init/validation.ts)
that runs after discovery and before compose generation in both the
--auto and interactive init paths:

- Candidate dedupe: collapse same-package duplicate scripts (dev +
  start) and drop root-level aggregator scripts that just delegate to
  a workspace package's own dev script (turbo --filter, dotnet run
  --project, pnpm --cwd), which is what actually produced the
  reported web/web-2 and phantom "backend" duplicates.
- Port collision handling: reassign colliding HTTP ports to the next
  free port (ascending) and rewrite the container command.
- Runtime detection: flag non-JS services (csproj/fsproj, go.mod,
  Cargo.toml, pyproject.toml, mix.exs, Gemfile, or command sniffing —
  including root aggregator commands that target another dir) and
  use an obviously-wrong alpine:3 placeholder image with a TODO
  comment instead of silently defaulting to bun-node.
- Backing-service detection: surface postgres/mysql/redis/temporal/
  kafka/rabbitmq/mongodb signals from dependencies, prisma schema,
  and .env* key names (values never read) as warnings + a compose
  header comment, without auto-scaffolding them.
- Existing-compose pointer: if a repo-root docker-compose*.yml already
  exists, point at it as ground truth instead of re-deriving.

renderCompose gains header/service comment injection (idempotent
post-process over the stringified YAML). buildDiscoveredComposeAuto
and ComposeWizardInput are now exported for direct pipeline testing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both init paths now tell first-time users/agents that full *.hack
routing needs hack global install (sudo, machine-wide DNS/CA) — field
agents hit this as a late surprise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@roodboi roodboi merged commit 9dd469f into main Jul 8, 2026
4 checks passed
@roodboi roodboi deleted the feat/init-discovery-validation branch July 8, 2026 01:30
roodboi pushed a commit that referenced this pull request Jul 8, 2026
## 3.3.0 (2026-07-08)

* Merge branch 'docs/partial-adoption' into feat/init-discovery-validation ([064db0e](064db0e))
* Merge pull request #58 from hack-dance/feat/init-discovery-validation ([9dd469f](9dd469f)), closes [#58](#58)
* feat(init): add post-discovery validation pass for hack init ([6b50b76](6b50b76))
* feat(init): surface the hack global install requirement in init output ([739a581](739a581))
* docs: document partial adoption (backing-services-only) as a valid hack setup ([871a247](871a247))

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 739a581776

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/commands/project.ts
Comment on lines +4481 to +4483
const dedupe = dedupeCandidates({ candidates: input.candidates });
const selectedCandidates = selectAutoCandidates({
candidates: input.candidates,
candidates: dedupe.selected,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve distinct root dev: services during auto init*

Here auto init feeds only dedupe.selected into service selection. Because the new package-level dedupe keeps a single script per packageId, a single-package repo with distinct scripts like dev:web and dev:api (not aggregators; no workspace package candidates to match) will generate only one service and silently omit the other. Please keep all distinct dev:* candidates unless they are proven aggregators or true duplicates.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in PR #59 (or as noted): dedupeCandidatesByPackage now groups by (package, script suffix): distinct dev:web/dev:api scripts in a single-package repo are distinct services and all survive; only same-service variants (dev vs start/serve/watch, same suffix) collapse. Regression test added.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant