Skip to content

feat(init): auto-update .gitignore + tighter tagline#31

Merged
justi merged 3 commits intomainfrom
feat/init-gitignore-and-tagline
Apr 27, 2026
Merged

feat(init): auto-update .gitignore + tighter tagline#31
justi merged 3 commits intomainfrom
feat/init-gitignore-and-tagline

Conversation

@justi
Copy link
Copy Markdown
Owner

@justi justi commented Apr 27, 2026

Summary

Two small but unrelated wins, bundled because they're both single-commit and low-risk:

1. Tagline rewrite

The cryptic Your side project died at 80%. Bring it back in one prompt. got swapped for Your agent forgot the ADR you wrote 30 prompts ago. — the literal failure mode users hit. No metaphor decoding required.

2. revive init auto-updates .gitignore

A common onboarding stumble: user runs revive init, then git add .revive/static.md — git silently skips it because the user's .gitignore has .revive/* (or similar) and no exception. The "checked in" workflow that README documents quietly fails.

cmd_init now calls a new maybe_update_gitignore helper:

  • Skip silently if not in a git repo, no .gitignore exists, or static.md is already trackable.
  • Append a canonical block (.revive/* + !.revive/static.md) with an explanatory header comment.
  • Warn (don't fail) when a directory-level .revive/ rule blocks the un-ignore — git semantics don't let ! rescue a file inside a fully-ignored directory; user needs to manually fix.

Test plan

  • 4 new tests cover: no .gitignore (no-op), .revive/* (append + verify trackable), already-correct (idempotent), .revive/ directory rule (warning emitted, exit 0 preserved)
  • Live smoke in a throwaway repo: existing rules preserved, exception appended, git check-ignore confirms static.md is now tracked
  • bats tests/ — 130/130 pass
  • shellcheck bin/revive install.sh clean

🤖 Generated with Claude Code

justi added 2 commits April 27, 2026 16:05
"Your side project died at 80%. Bring it back in one prompt." was
cryptic — readers had to guess what 80% referred to (project
abandonment? completion?), and nothing in the line connected to
the actual problem the tool solves (agent context rot in long
sessions).

Replace with the literal failure mode users hit in practice:
"Your agent forgot the ADR you wrote 30 prompts ago." Names the
pain directly, no metaphor decoding required. The next paragraph
already explains the mechanism, so the tagline can stay terse.
A common onboarding stumble: user follows the README, runs
`revive init`, then `git add .revive/static.md` — git silently
skips the file because their .gitignore has `.revive/*` (or
similar) and no exception. The "checked in" workflow the README
documents quietly fails.

`cmd_init` now calls `maybe_update_gitignore` after writing
static.md. Logic:

- Skip silently if not in a git repo, no .gitignore exists, or
  `git check-ignore` says the file is already trackable.
- Otherwise append a small canonical block:
    .revive/*
    !.revive/static.md
  with a header comment explaining what gets tracked vs not.
- Re-run `git check-ignore`. If a directory-level `.revive/`
  rule still suppresses the un-ignore (git semantics: `!`
  cannot rescue a file inside a fully-ignored directory), print
  a warning telling the user how to fix it.

4 new tests cover: no .gitignore (no-op), `.revive/*` (append +
verify trackable), already-correct (idempotent — line count
unchanged), `.revive/` directory rule (warning emitted, exit 0
preserved).
Copilot AI review requested due to automatic review settings April 27, 2026 07:08
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves onboarding and messaging by updating the project tagline and making revive init proactively fix a common .gitignore misconfiguration that prevents .revive/static.md from being tracked as intended.

Changes:

  • Update README tagline to a clearer, failure-mode-based statement.
  • Add maybe_update_gitignore to revive init to append a canonical .revive/* + !.revive/static.md block when static.md is currently ignored (and warn when directory-level ignore rules prevent the fix from taking effect).
  • Add Bats tests covering the .gitignore update behavior (no-op, append, idempotent when already correct, warn-on-directory-rule).

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.

File Description
bin/revive Calls a new helper from cmd_init to update .gitignore so .revive/static.md becomes trackable; warns when un-ignore can’t work due to directory-level rules.
tests/revive.bats Adds tests for revive init’s .gitignore auto-update and warning behavior.
README.md Replaces the tagline with a clearer, more literal description of the problem the tool solves.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Two issues codex flagged on the original gitignore-auto patch:

[P2] Broad dot-dir rules left static.md untrackable
- A repo with `.revive/`, `.revive`, or even `.*` / `.*/` already
  ignores the parent directory. Git semantics: `!` cannot rescue
  a file inside a fully-ignored directory.
- The canonical block now leads with `!.revive/` to un-ignore the
  parent first, then re-ignores contents with `.revive/*`, then
  re-includes static.md with `!.revive/static.md`.
- The "warns when a directory-level .revive/ rule blocks" test
  flipped to "un-ignores even with a directory-level rule" — the
  former failure mode no longer happens. Added a parallel test
  for `.*` to cover the broad-rule case.

[P3] Read-only .gitignore aborted `revive init`
- Under `set -e`, `cat >> .gitignore` on a read-only file killed
  cmd_init even though the gitignore update is best-effort.
- Pre-check writability with `[[ -w .gitignore ]]`. If not
  writable, print the exact lines the user needs to add and
  return 0 — static.md is already created at this point.
- New test exercises the read-only path: chmod -w .gitignore,
  trap restores write perm so teardown doesn't break.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the revive init onboarding flow by making .revive/static.md reliably trackable in git (via a best-effort .gitignore auto-update) and updates the README tagline to a more literal/clear failure mode description.

Changes:

  • Add maybe_update_gitignore to append a canonical .revive ignore/un-ignore block when static.md is currently gitignored.
  • Add Bats coverage for .gitignore update behavior across common ignore patterns and failure modes.
  • Update the README tagline.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.

File Description
bin/revive Calls new maybe_update_gitignore from cmd_init and appends a canonical .gitignore block to un-ignore .revive/static.md when needed.
tests/revive.bats Adds tests validating .gitignore no-op/idempotency/update behavior and read-only warning behavior.
README.md Replaces the top-level tagline.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@justi justi merged commit fd8c813 into main Apr 27, 2026
7 checks passed
@justi justi deleted the feat/init-gitignore-and-tagline branch April 27, 2026 13:26
justi added a commit that referenced this pull request Apr 27, 2026
* docs(readme): document the post-compact refresh trigger

Cadence section now lists four triggers (was three): first prompt,
every-N counter, time-gap, and the new post-compact override.
Quick start mentions install-hook now wires both UserPromptSubmit
and PostCompact.

* feat: refresh trigger after `/clear`

Sibling to the post-compact trigger from #30. `/clear` wipes more
than `/compact` (full conversation reset), but the recovery path is
identical — re-inject the brief on the next prompt, bypassing
cadence. Wired through Claude Code's `SessionStart` hook with
`matcher: "clear"`, the documented dedicated signal.

Implementation:
- New `cmd_mark_clear` writes the same `.claude/revive-compact.signal`
  as `cmd_mark_compact`. Two commands so settings.json reads naturally
  and hook.log distinguishes the source.
- `cmd_install_hook` now wires three hooks. Refactored the upsert
  helper to take an optional `matcher`, so SessionStart{clear} stays
  distinct from any user-added SessionStart{startup} or {resume} entry
  (idempotency key: event + matcher + command).
- `cmd_doctor` adds a third hook check via the existing
  `_doctor_check_hook` helper (`SessionStart` + `revive mark-clear`).
- README cadence section gains trigger #5; install-hook line now
  lists all three events.

6 new tests cover: signal write, help-text surface, settings.json
shape (matcher field present), 3-hook idempotency, doctor warn on
missing SessionStart, doctor green path with all three hooks.

* release: v0.2.0

Headline: context-loss recovery. Refresh now fires immediately after
`/compact` (#30) and `/clear` — the two moments when an agent has
just lost most of its working memory and the brief gives the highest
ROI. Three hook events wired by `install-hook`: UserPromptSubmit,
PostCompact, SessionStart(matcher=clear).

Also since v0.1.19:
- `revive init` auto-fixes `.gitignore` so static.md is trackable (#31)
- README tagline rewrite (#31)

* fix(doctor): validate SessionStart matcher (codex P3)

`_doctor_check_hook` accepted any SessionStart entry pointing at
`revive mark-clear` regardless of its `matcher` value. A user who
hand-wired SessionStart{startup} → mark-clear (or no matcher at
all) would pass doctor, but `/clear` would never trigger that
hook. Codex flagged the false-positive on the v0.2.0 PR.

Two changes:

1. The helper takes an optional 3rd arg `matcher`. When set, the
   jq query also asserts `(.matcher // "") == $m` so only the
   intended entry counts. Doctor labels include the matcher in
   parens — `SessionStart(clear) hook installed`.

2. The grep fallback used to override a legitimate "no match"
   from jq because it ran on any non-zero jq exit. Distinguish
   jq's exit codes:
     - 0 → match;
     - 1 → legitimate no-match (trust it, skip grep);
     - ≥2 → jq error or absent → grep fallback (best-effort,
            can't tie matcher to command across JSON lines).
   Without that, the matcher check would have been silently
   defeated whenever jq returned 1 and grep happened to find
   the command string anywhere in the file.

Also: `set -e` interaction. The naive `jq ...; rc=$?` pattern
would abort the function on jq's non-zero exit before the
assignment. Wrapping in `if jq ...; then rc=0; else rc=$?; fi`
preserves the code.

Tests:
- "doctor warns when SessionStart entry has wrong matcher" — new
  regression test for codex P3, hand-crafts settings.json with
  matcher=startup pointing at mark-clear, asserts the warning.
- Existing missing-SessionStart and all-three-hooks tests
  updated to expect the `(clear)` label.
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.

2 participants