Skip to content

feat: override merge mode for generate-context#47

Draft
joshbouncesecurity wants to merge 6 commits intoknostic:masterfrom
joshbouncesecurity:feat/issue16-18-override-mode
Draft

feat: override merge mode for generate-context#47
joshbouncesecurity wants to merge 6 commits intoknostic:masterfrom
joshbouncesecurity:feat/issue16-18-override-mode

Conversation

@joshbouncesecurity
Copy link
Copy Markdown
Contributor

Summary

When generate-context detects a manual override file (OPENANT.md / OPENANT.json), it now prompts the user to choose:

  • use — apply the override as-is, skip the LLM call.
  • merge — feed the override into the LLM alongside other sources.
  • ignore — skip the override, generate from scratch.

Adds --override-mode <use|merge|ignore> to bypass the prompt for CI/automation. --force is kept as a backward-compatible shortcut for --override-mode ignore. In non-interactive environments (no TTY) the prompt is skipped and use is the default.

Previously, override files were all-or-nothing — either they fully replaced LLM generation or were ignored entirely, with no way to combine developer-provided hints with LLM analysis.

Depends on #41 (item 17 — generate-context CLI command). Please merge that first; the diff here is the override-mode addition only.

Addresses item 18 from #16 (does not close the issue).

Test plan

  • Interactive prompt offers use/merge/ignore when an override exists.
  • --override-mode use skips the LLM and emits the override verbatim.
  • --override-mode merge feeds the override into the LLM (verify with --show-prompt).
  • --override-mode ignore ignores the override.
  • --force still works as a shortcut for --override-mode ignore.
  • --force and --override-mode are mutually exclusive (CLI rejects both).
  • No-TTY default is use.

joshbouncesecurity and others added 6 commits May 4, 2026 21:11
Add a standalone `openant generate-context` command so users can
generate application_context.json as a discrete pipeline step when
running individual commands (parse → generate-context → analyze → verify).

Also wire up auto-discovery of application_context.json in both
the Go CLI (project scan dir) and Python CLI (output dir, repo path,
input file dir) so `analyze` and `verify` pick it up automatically
without requiring `--app-context` every time.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: update PIPELINE_MANUAL.md for generate-context CLI command

Update Step 4 to document the new `openant generate-context` command
as the primary way to generate application context. Add note about
auto-discovery in analyze/verify. Update examples and quick reference.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: update remaining docs for generate-context CLI command

Update CURRENT_IMPLEMENTATION.md, README.md, and DOCUMENTATION.md to
reference `openant generate-context` as the primary command and note
the auto-discovery behavior in analyze/verify.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cover the `_find_app_context` helper used by `analyze` and `verify` to
locate application_context.json automatically when --app-context is
not provided.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When a manual override file (OPENANT.md) is detected, users can now choose
how to handle it: use as-is, merge into LLM context, or ignore. An
interactive prompt appears by default; --override-mode flag bypasses it.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds unit tests for the override-mode functionality of generate-context:

- test_override_mode.py: covers find_override_file() (none/found/priority),
  gather_context_sources() merge behavior, and the dispatch logic of
  generate_application_context() across "use", "ignore", "merge", and
  legacy force_regenerate paths. Also covers the Python CLI's argparse
  validation of --override-mode choices.
- test_go_cli.py: extends TestGenerateContext with parametrized tests for
  each --override-mode value, an invalid-value rejection test, and a
  no-TTY default test ensuring the interactive prompt is suppressed when
  stdin is piped. Also wires run_cli() to default stdin to a closed pipe
  so subprocess tests don't accidentally inherit pytest's TTY.

All 128 tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Round 1 PR review fixes for the override-mode feature:

- Add 30s timeout on the interactive override-mode prompt (Go CLI). The
  previous bufio.ReadString call would block forever if a TTY was detected
  but no user was actually present (detached terminals, some CI runners).
  Now the prompt clearly advertises the timeout and falls back to "use".
- find_override_file (Python) now requires a regular file via .is_file()
  rather than .exists(). This matches the Go CLI's IsDir() guard and
  prevents merge mode from crashing with IsADirectoryError when a
  directory happens to share an override filename. Updated the test that
  previously documented the unsafe behavior, and added a regression test.
- Extract the 10000-char merge-mode truncation cap into a named constant
  MAX_OVERRIDE_MERGE_CHARS so the magic number isn't duplicated.
@joshbouncesecurity
Copy link
Copy Markdown
Contributor Author

Manual verification

Requires API key. Drop an OPENANT.md (or OPENANT.json) in the target repo first.

  • openant generate-context <repo> (interactive TTY): prompts to choose use / merge / ignore.
  • openant generate-context <repo> --override-mode use: skips the LLM call entirely; emits the OPENANT.md content as the application context.
  • openant generate-context <repo> --override-mode merge --show-prompt: prompt sent to the LLM includes the override file content + the merge supplement.
  • openant generate-context <repo> --override-mode ignore: ignores the override; generates from scratch.
  • openant generate-context <repo> --force: behaves identically to --override-mode ignore.
  • openant generate-context <repo> --force --override-mode merge: rejected with a clear mutual-exclusion error.
  • No-TTY: openant generate-context <repo> < /dev/null (or piped through CI): skips the prompt, defaults to use.
  • Priority: with both OPENANT.md and OPENANT.json present, the .md wins.
  • Note: depends on PR feat: add generate-context CLI command with auto-discovery #41; please merge that first.

@joshbouncesecurity
Copy link
Copy Markdown
Contributor Author

Local test results

Built and reinstalled openant-core from this branch. Created a tiny fixture (app.py + OPENANT.md declaring application_type: cli_tool) and exercised the new flag.

Commands run:

go build -o openant.exe ./
pip install -e libs/openant-core
openant --json generate-context <fixture> --override-mode merge --show-prompt
openant generate-context <fixture> --force --override-mode merge       # mutex check

Outcome (per checklist):

  • --override-mode merge --show-prompt: API call ran with Sonnet (~6.6s), Source: merged, generated context returned application_type: cli_tool (matching the override), confidence: 100%
  • The JSON-mode output's prompt_format field is populated and clearly contains the OPENANT.md override content (Prints hardcoded 'hi' string on invocation, Hardcoded 'hi' return value - this is the intended functionality, etc.) ✅
  • --force --override-mode merge: rejected with Error: --force and --override-mode are mutually exclusive
  • generate-context --help lists --override-mode and explains the three modes ✅
  • Did not run the use / ignore / interactive-prompt / no-TTY / .md-vs-.json priority paths in this manual pass — those are covered by tests in the diff.

Note for the maintainer (small UX nit): --show-prompt only surfaces the formatted prompt when the global --json flag is also set (since the prompt goes through _output_json). The prompt-format text never appears in the friendly stdout output, so a user typing openant generate-context --show-prompt without --json sees no visible prompt. Worth either documenting that pairing or always emitting the prompt to stdout when the flag is passed.

Reported cost: $0.00 (Sonnet, ~6.9s).

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