Skip to content

klasp setup: one-command first-run flow + sensible install/adopt defaults #103

@liam-ai-reality

Description

@liam-ai-reality

Why

Today's first-run experience requires three commands in a specific order, with klasp.toml defaults that don't match what most users actually have installed. End-to-end test on a fresh repo (clean adopt → install → doctor):

$ klasp init --adopt --mode mirror     # writes klasp.toml with [gate].agents = ["claude_code", "codex", "aider"]
$ klasp install --agent claude_code    # only one of the three agents on this machine
$ klasp doctor
FAIL  hook[codex]:  /private/tmp/foo/AGENTS.md not found; re-run `klasp install`
FAIL  hook[aider]:  /private/tmp/foo/.aider.conf.yml not found; re-run `klasp install`

Two FAILs out of the gate, on a fresh, correct install — because klasp.toml is asking for agents the user doesn't run. To get a green doctor the user has to either (a) edit klasp.toml down to the agents they have, or (b) klasp install --agent all which provisions agent surfaces they don't use. Both are friction; neither is the right default.

A second friction surfaced the same session: when multiple detected gates declare the same check name (e.g. Husky pre-commit runs pnpm lint AND Lefthook also runs pnpm lint), the generated klasp.toml has two [[checks]] name = "lint" entries. Klasp_core tolerates it but it's confusing in klasp doctor output (two path[lint] lines) and ambiguous if users want to disable just one.

Proposal

Combine four changes that converge on a clean first-run loop. Each is small individually; together they replace the current 3-command-with-edits flow with a 1-command-and-done flow.

1. New klasp setup orchestrator

Single entry point that runs adoption + agent selection + install + doctor in order, with sensible defaults at every step.

klasp setup                      # default — non-interactive, detect everything, write green config
klasp setup --interactive        # walk through detected gates and agents with prompts
klasp setup --dry-run            # print the plan but write nothing

Behaviour (non-interactive default):

  1. Detect existing gates (re-uses klasp::adopt::detect::detect_all).
  2. Detect installed agents on this machine (sniff ~/.claude/, ~/.codex/, ~/.aider* or whatever the agent surfaces already check during klasp install auto-detect).
  3. Compute the intersection: [gate].agents = detected agents only.
  4. Write klasp.toml with that narrowed agents list and the adopted checks.
  5. Run klasp install --agent all against the narrowed list (no surface installs without a corresponding agent on disk).
  6. Run klasp doctor and report.
  7. Single green summary or actionable failure message — no two-step "now run klasp doctor" instruction at the end of inspect output.

Interactive mode adds y/n prompts before steps 4 and 5 plus a "which gates do you want to mirror?" multi-select before step 4.

The current 3 commands stay supported and unchanged for scriptable / CI use; setup is additive sugar.

2. Default [gate].agents to detected agents (not all three)

Today, klasp init --adopt --mode mirror always writes agents = ["claude_code", "codex", "aider"]. Change the writer to:

  • If the calling context knows which agents the user has (from setup, or from --agent <name> passed to init), narrow [gate].agents to that.
  • Otherwise default to a single agent the user is most likely to be running — claude_code if ~/.claude exists, else fall through to today's three-agent default with a comment explaining the user can drop entries.

This change alone removes the most common doctor-FAIL cause for fresh installs.

3. Auto-suffix duplicate check names

In klasp/src/adopt/writer.rs, when two ProposedChecks land with the same name, suffix the second one with the gate type that produced it: lint-husky, lint-lefthook. The suffix only kicks in on collision; the first lint keeps the bare name.

Reasoning: most users will have one gate manager. The suffix only affects polyglot-gate repos where the rare-but-real "I have BOTH Husky AND Lefthook" case wins clarity at the cost of a slightly less elegant name. Doctor output becomes self-documenting:

OK    path[lint-husky]: `pnpm` found in PATH
OK    path[lint-lefthook]: `pnpm` found in PATH

instead of two path[lint] lines that look like a typo.

4. klasp install warn when narrower than [gate].agents

When the user runs klasp install --agent claude_code against a klasp.toml whose [gate].agents includes more than claude_code, klasp install should warn: "klasp.toml lists agents codex, aider that this install will NOT cover; doctor will report them as missing." It already has the data — the warning is one printf and a comparison.

Acceptance criteria

  • klasp setup exists as a subcommand and runs the full detect → narrow → write → install → doctor sequence end-to-end.
  • On a fresh repo with ~/.claude/ present and no other agent dirs, klasp setup produces a klasp.toml with [gate].agents = ["claude_code"] and klasp doctor exits 0 with no FAILs.
  • klasp setup --interactive prompts before writing files and before installing surfaces.
  • klasp setup --dry-run prints the plan and writes nothing.
  • When two ProposedChecks collide on name, the second is suffixed with its gate type (lint-husky, lint-lefthook); a unit test in klasp/src/adopt/writer.rs covers the collision case.
  • When klasp init --adopt --mode mirror is run without --agent and finds ~/.claude/ only, the generated klasp.toml has [gate].agents = ["claude_code"]. When it finds nothing, it falls through to today's default with the "edit me" comment.
  • klasp install --agent <single> against a multi-agent klasp.toml emits a stderr WARN listing the uncovered agents; the install itself still succeeds.
  • Integration tests cover: fresh repo with claude only, fresh repo with all three, fresh repo with adopt fixtures from First-run gate adoption: detect and mirror existing pre-commit/Husky/Lefthook setups #97, dry-run, interactive Y/N flows.
  • docs/setup.md (or extended docs/adopt.md) documents the new flow with a copy-paste-ready first-run example.

Non-goals

  • Changing how individual surfaces install (codex/aider already have managed-block / config-merge logic — keep it).
  • Adding new agent surfaces; this is purely an orchestration + defaults change.
  • Replacing klasp init, klasp install, klasp doctor — those stay as scriptable primitives. setup is sugar over them.
  • Solving doctor false-positive 'schema drift' on codex hook with managed-block append #102 (doctor codex drift false-positive); orthogonal.

Surfaced via

End-to-end test of #96 (audit recipes) + #97 (klasp init --adopt) on 2026-05-08. Three of the four changes here address concrete friction observed in that session; the fourth (orchestrator) ties them together so a new user can go from git init to green doctor in one command.

Severity / size

Medium. Orchestrator is the largest piece (~200 LOC + tests + interactive prompt handling). The three smaller fixes are each <30 LOC self-contained changes that could ship independently before the orchestrator if useful. Suggest landing in this order:

  1. Default [gate].agents narrowing (smallest, highest user impact, no new surface).
  2. Duplicate-name suffix (mechanical, isolated to writer.rs).
  3. klasp install --agent X warn-on-narrower (one log line).
  4. klasp setup orchestrator (uses the three above).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions