feat(init): teach the next step and mark detected targets - #166
Merged
Conversation
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>
Merged
Open
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.
What
Dogfooding
ion initon a real project (bloqade-website) surfaced two progressive-prompting gaps on the init journey. Both are fixed here, test-first.1.
initended 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:ion add <source>/ion search <query>ion addThe
--jsonenvelope gained adata.nextarray:2. No-TTY
inittold the agent more than the human (channel mismatch)--jsonexposed a per-target"detected": trueflag, but the human plain-text list showed nothing and hard-coded--target claudein the recovery example. Now the human list marks(detected)and prefers a detected target in the example:Changes
src/commands/init.rs— next-step helpers (next_steps_after_init) +(detected)markingsrc/builtin_skill.rs— exposeSKILL_NAMEso the next-step counter excludes the Ion-managed builtintests/json_integration.rs,tests/scenario_tests.rs— three failing-first tests pinning the guidance in both channelsskills/dogfooding-ion/SKILL.md— logged the second-pass findingsNotes
ion-cli = { type = "local" }is intentional (skipped by fetch/validate/update, refreshed viarefresh_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