Skip to content

feat(init): teach the next step and mark detected targets - #166

Merged
Roger-luo merged 3 commits into
mainfrom
init-next-step-guidance
Jul 18, 2026
Merged

feat(init): teach the next step and mark detected targets#166
Roger-luo merged 3 commits into
mainfrom
init-next-step-guidance

Conversation

@Roger-luo

Copy link
Copy Markdown
Owner

What

Dogfooding ion init on a real project (bloqade-website) surfaced two progressive-prompting gaps on the init journey. Both are fixed here, test-first.

1. init ended with no next step (both channels)

The old output stopped at Created Ion.toml with N target(s) — a dead end for a human and an agent. Now a single, state-aware next-step line renders from one source of truth to both channels:

  • fresh project → ion add <source> / ion search <query>
  • skills already declared → ion add

The --json envelope gained a data.next array:

"next": ["ion add <source>", "ion search <query>"]

2. No-TTY init told the agent more than the human (channel mismatch)

--json exposed a per-target "detected": true flag, but the human plain-text list showed nothing and hard-coded --target claude in the recovery example. Now the human list marks (detected) and prefers a detected target in the example:

Available targets:
  claude -> .claude/skills (detected)
  cursor -> .cursor/skills
  windsurf -> .windsurf/skills
Re-run with --target <name> to select targets (e.g. --target claude).

Changes

  • src/commands/init.rs — next-step helpers (next_steps_after_init) + (detected) marking
  • src/builtin_skill.rs — expose SKILL_NAME so the next-step counter excludes the Ion-managed builtin
  • tests/json_integration.rs, tests/scenario_tests.rs — three failing-first tests pinning the guidance in both channels
  • skills/dogfooding-ion/SKILL.md — logged the second-pass findings

Notes

ion-cli = { type = "local" } is intentional (skipped by fetch/validate/update, refreshed via refresh_global) — documented, not changed.

Test plan

  • cargo fmt --all
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo nextest run — 800/800 ✅

🤖 Generated with Claude Code

Roger-luo and others added 3 commits July 17, 2026 22:33
Driving `ion init` on a real project surfaced two progressive-prompting
gaps, both now fixed with failing-first tests:

- `ion init` ended at a bare "Created Ion.toml" confirmation with no
  next-step guidance in either channel. Add a state-aware next step
  (fresh project -> `ion add`/`ion search`; skills already declared ->
  `ion add`) rendered from one source of truth to the human text and a
  new `data.next` array in the JSON envelope.
- The no-TTY target list exposed a per-target `detected` flag to agents
  via `--json` but showed nothing to a human. Mark `(detected)` on
  targets whose directory already exists and prefer a detected target in
  the `--target <name>` recovery example.

Also expose `builtin_skill::SKILL_NAME` so the next-step counter can
exclude the Ion-managed `ion-cli` skill when deciding which step to show.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`ion init` previously only offered AGENTS.md setup interactively (TTY-gated)
and only when a language template was detected — so piped/agent runs and
projects with no recognized stack got no AGENTS.md, and an existing CLAUDE.md
was never migrated (only `ion migrate` did that). Rework init to always
ensure an ion-managed AGENTS.md, in every channel:

- Create AGENTS.md from a detected language template, or a new
  `builtin:generic` scaffold when no language matches.
- Migrate an existing CLAUDE.md into AGENTS.md (rename + symlink back);
  a genuine two-file conflict is skipped safely with an init-appropriate note.
- Leave a hand-written AGENTS.md intact and make it ion-managed by symlink
  only — no `[agents]` template is attached to the user's own content.
- Whenever a template is applied, the first next step (human list + JSON
  `data.next`) prompts filling in AGENTS.md.
- New `data.agents_md` = {action: created|migrated|existing|skipped|disabled,
  template?} mirrors the human summary for agents.
- `--no-agents` opts out of the whole thing.

`agents init`'s file-work is extracted into a non-printing
`agents::apply_template` so both commands share it without double-emitting a
JSON envelope. `migrate_claude_md` gains a `rename_without_prompt` param;
`ion migrate` keeps its conservative `--yes` behavior (skip the rename).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Several tests create throwaway git repos and commit into them. CI runners
have no default git identity, so `git commit` fails with exit 128 and a later
`git rev-parse HEAD` reports "ambiguous argument 'HEAD'", flaking the Test job
on both ubuntu and macOS. Configure a deterministic user.name/user.email and
init.defaultBranch before running nextest.

Reproduced locally: with an empty global git config the git unit tests fail
with the exact error; with an identity configured they pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Roger-luo
Roger-luo merged commit 17f4f75 into main Jul 18, 2026
4 checks passed
@Roger-luo
Roger-luo deleted the init-next-step-guidance branch July 18, 2026 03:10
@github-actions github-actions Bot mentioned this pull request Jul 18, 2026
@github-actions github-actions Bot mentioned this pull request Aug 5, 2026
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