Repository navigation
fix(agents): build every onboarding prompt from one discovery-first builder - #322
Merged
Merged
Conversation
…mpt and add the env secrets threat model The `hack global dns activate|deactivate` authorize closures move into createNativeDnsAuthorizer (src/lib/native-domain-dns-authorization.ts) with injectable interactivity, confirmation and administrator prompt. A failed sudo -v now throws NativeDnsAdministratorAuthorizationError (closed outcome "authorization-failed" and failure class; message unchanged). Tests wire the authorizer into the real activation/deactivation flows and host effect boundary and prove: sudo -v runs before every privileged and file effect, a failed prompt is authorization-failed (not denied) and changes nothing, and a decline or a non-interactive run never reaches sudo. Adds docs/security/env-secrets-threat-model.md (HACK-1127), linked from docs/env.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…efaults
tests/global-dns-authorizer-wiring.test.ts checks, on the TypeScript
syntax tree of src/commands/global.ts, that handleGlobalDnsActivate and
handleGlobalDnsDeactivate each build exactly one authorizer with
createNativeDnsAuthorizer({ action: <own action>, domain }), pass it to
createNativeDnsHostDependencies, and run their flow with those
dependencies. The only other authorizer allowed is the decline-only
`async () => false` on the deactivate verify-only path.
tests/native-domain-dns-authorization.test.ts now also covers the
production defaults: the default interactivity check requires a stdin
TTY before confirming, and the default confirmation declines an
explicitly non-interactive run before sudo. The administrator prompt
stays a fake, so no test reaches real sudo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uilder `hack init --with`, `hack agent onboard`, `hack agent init` and the `hack-init` MCP prompt now call one builder in src/agents/onboarding-prompt.ts. It runs the corrected repo inventory (bun.lock, nested workspace lockfiles, non-JS runtimes, runtime pins, explicit discovery limits) and renders it before the phases. Each prompt is exactly frame.before + core + frame.after; the core is byte-identical for the same repo and only a fixed, value-free framing line differs. Mode, project name and dev host now follow repo state, so the init handoff always adopts the `.hack/` it runs after; its framing says whether this run scaffolded it. The MCP prompt takes an optional repoRoot; without it nothing is scanned and the core says no inventory ran. MCP inventory failures return closed, value-free errors. HACK-1137 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Authored .hack/hack.project.json projects now receive the same HACK_* runtime host metadata as Compose-file and native image projects, on the authored native path (up/restart; exec and run inherit) and the authored Compose renderer. The config compiler accepts optional env_metadata.runtime values for declared workloads (closed reserved key set, 64 KiB per value, no NUL) and reports them as public `runtime` bindings below managed values and every authored directive. Host entries never receive them. The values come from the shared runtime-host-metadata builder, fed with the compiler's effective routing hosts. runtime-core adds runtime bindings to public workload environment, never to private delivery. HACK-1263 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re guards Add a prepareCommand-level regression test: authored Compose `up` through the source CLI renders the reserved runtime metadata keys, and HACK_COMPOSE_PROJECT equals the generation store's hack-nc-... project for the default and a --branch instance. A checkout replaced between metadata selection and store open refuses before any Compose effect. Cover the TS wire guards: runtime metadata with non-reserved keys, undeclared workloads or non-text values refuses before the compiler spawns, and host reports carrying runtime bindings are rejected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…no-shell clients - Pin the value-free hack-init MCP catch: an injected builder failure whose message carries a path and a credential value must surface only the closed `<code>: hack-init could not inventory the repo.` text. - Pin the `<dev_host>` placeholder for an existing setup with no dev_host. - Give interactive `hack init` a terminal seam (TTY check, prompts, service wizard, agent-step prompts) and test that its `--with` handoff frames a scaffolded run as `created` and a kept `.hack/` as `existing`. - The /hack-init skill and canonical agent-setup guidance tell no-shell clients to pass `repoRoot` to the hack-init MCP prompt so it includes the repo inventory; renders, plugins, fingerprints and revision regenerated. - Trim repoRoot once so the presence check and the resolved path agree. HACK-1137 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tadata-b14 Conflicted files: none. The two change sets touch disjoint files, so git merged them automatically. Regenerated surfaces after the merge (no resulting diff): - bun run generate:agent-plugins - bun run docs:cli-reference - checked-in renders (.codex/skills/hack-cli, .codex/skills/hack-init, .claude/skills/hack-init, .cursor/rules/hack.mdc) compared byte-equal with their render functions. integration-revision.ts and KNOWN_RENDER_FINGERPRINTS keep the values from wf/e1-authored-metadata-b14; agent-instruction-source and integration-ownership tests pass unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…der-b14 Conflicted files and resolutions: - src/agents/integration-revision.ts: set to bd15ee2d251b, the value tests/agent-instruction-source.test.ts computes for the merged instruction source. - src/agents/integration-ownership.ts: KNOWN_RENDER_FINGERPRINTS is the append-only union of both sides, plus the merged renders requested by tests/integration-ownership.test.ts (hack-cli-skill 88900097f7eb18a752de31bb, cursor-rules 07e49d3c2b05b93b6c49adfd). - plugins/hack/rules/hack.mdc, plugins/hack/skills/hack-branches/SKILL.md, plugins/hack/skills/hack-cli/SKILL.md, plugins/hack/skills/hack-diagnose/SKILL.md, plugins/hack/skills/hack-env/SKILL.md: regenerated with bun run generate:agent-plugins. - .codex/skills/hack-cli/SKILL.md, .cursor/rules/hack.mdc: re-rendered through installCodexSkill/installCursorRules with an explicit project root; byte-equal to the renderers. - examples/basic/AGENTS.md, examples/basic/CLAUDE.md: re-rendered through upsertAgentDocs with an explicit project root. src/agents/instruction-source.ts merged cleanly. .claude/skills/hack-init and .codex/skills/hack-init re-rendered as no-ops. docs/reference/cli.md regenerated with no diff. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-parents onto next after the previous stacked PR squashed in; next's tree equals 6710d52, which this branch already contains, so the branch tree is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Final behavior
Issue: HACK-1137 (unit E2).
hack init --with,hack agent onboard,hack agent initand thehack-initMCP prompt all call one builder insrc/agents/onboarding-prompt.ts(buildOnboardingPrompt). Each one embeds the same repo inventory frombuildInitAssistantReport(the corrected W12/fix(agents): correct onboarding inventory and harden onboarding prompt #291 inventory:bun.lock/bun.lockb, nested workspace lockfiles and package-manager conflicts, non-JS runtimes, runtime pins by name, and explicit discovery limits).## Repo inventory (pre-computed by Hack)section comes before Phase 1. Phase 1 now starts by confirming that inventory.frame.before + core + frame.after.renderOnboardingCoreproduces the core, which is byte-identical for every entry point on the same repo.renderOnboardingFrameowns the only per-entry text. That text is fixed and never repeats repo values:init --with: one leading line that says whether this run scaffolded.hack/or skipped init because.hack/already existed.agent init: keeps its trailinghack agent patternspointer.agent onboardand MCP: no framing. The MCP message envelope is unchanged.existing-projectwhen a.hack/project is found (values from its config), otherwisenew-project. The repo root is the enclosing hack project root, or thehack initroot when there is no project.init-assistant.tsno longer assembles a prompt. It exportsrenderInitAssistantInventory, and only the builder calls it.hack-initgains an optionalrepoRootargument. Relative values resolve against the session cwd. WithrepoRoot, the prompt matcheshack agent onboardfor that repo, andmode/projectName/devHostare ignored. Without it, nothing is scanned (the server cwd may be HOME or/) and the core statesNot run: … named no repoRoot. Inventory failures return closed, value-free protocol errors that never echo the path, config values or the underlying message:E_PROJECT_NOT_FOUND: Path not found., or<HackErrorCode>: hack-init could not inventory the repo..Behavior changes to review
hack init --withafter a fresh scaffold now hands off in existing-project mode, with the header "adopt the existing hack setup" and the instruction "refine.hack/, do not re-run init". Before, it said "stand up hack" and told the agent to runhack init --auto. The framing line says the scaffold is new. A post-init handoff always runs with.hack/present, so this is the only way it can share a core withagent onboard.dev_hostnow shows the placeholder<dev_host>instead of a guessed<slug>.hackor the new-project<project>.hack.localdefault. The removedresolveExistingInitHostwas the only producer of the guess.hack agent initnow reads.hack/config (name/dev host), so a malformed config fails it the same way it already failedhack agent onboard.agent onboard,init --withand the MCP prompt now include package.json script commands (the inventory's dev and setup scripts), which onlyagent initshowed before.No canonical guidance render changed (the
/hack-initskill, plugins and instruction sources are untouched), so plugin generation, fingerprints and the revision are unchanged. The CLI surface is unchanged, sodocs/reference/cli.mdwas not regenerated. Docs updated:docs/guides/agent-first-setup.mdanddocs/agent-guidance.md.Validation
tests/onboarding-entry-parity.test.ts:privateCliEnv(private HOME, isolated Docker client, empty PATH,HACK_NO_INTERACTIVE=1). The MCP prompt runs in-process overInMemoryTransport, so it also runs in CI.agent onboard,agent initand MCP (absolute and relativerepoRoot) all equalframe + renderOnboardingCore(collectOnboardingContext(repo)).init --auto --with claude(scaffolded) and a secondinit --auto --with codex(existing), both handoffs plusagent onboard,agent init --path apps/weband MCP (with conflicting caller mode, name and host) equal one shared core.repoRoot(the not-run core). Closed MCP refusals (missing path; native marker) never echo the path.buildOnboardingPrompt(.onboarding-prompt,init-assistant,setup,init-with-command.bun teston 15 focused files: onboarding, init-assistant, setup, init-with-command, agent-onboard-command, mcp-prompts, onboarding-handoff, integration-ownership, cli-spawn-env-isolation, agent-instruction-source, agent-plugin-generation, mcp, mcp-session-context, mcp-inspect-tools. Result: 163 pass, 0 fail.bun run --cwd packages/cli typecheck: 0 errors.bun run --cwd packages/cli check: 0 errors (the existing warnings are not in changed files). The changed tests were linted explicitly and are clean.Negative controls (source mutations, each restored afterward)
Each mutation below was killed by the parity test file:
agent onboardrenders without the inventory (the pre-change shape): parity test fails, and so does the static guard.agent initwraps the shared prompt in its own title: parity test fails.init --withframes an existing.hack/as freshly scaffolded: parity test fails.repoRoot: parity and refusal tests fail.projectNameleaks into the repo-derived core: parity test fails.The in-file negative-control test also checks that a dropped inventory signal, a missing inventory, a leaked frame, or a missing frame each produce a parity issue.
One mutation survived, as expected. Having
agent initpass thehack initroot instead ofstartDiris equivalent behavior: the builder resolves the enclosing project root itself.Remaining gaps
bun testsuite (CI mode) had not finished locally when this PR opened, so hosted CI is the gate for the rest of the suite.repoRootscanning is bounded only by the inventory's existing scan caps. A caller who passes/or HOME gets the same scan cost thathack agent init --path /has today.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.