Skip to content

Simplify CLI commands and fix query regressions#15

Merged
PhantomInTheWire merged 11 commits into
masterfrom
codex/cli-simplify-and-fix-ci
Apr 4, 2026
Merged

Simplify CLI commands and fix query regressions#15
PhantomInTheWire merged 11 commits into
masterfrom
codex/cli-simplify-and-fix-ci

Conversation

@PhantomInTheWire

@PhantomInTheWire PhantomInTheWire commented Apr 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • split the CLI into typed command/parsing modules while keeping main.rs as the orchestration entrypoint
  • simplify the CLI state model by using subcommands for query source and index kind, and require a single { schema, options } shape for create-from-schema
  • fix two CI regressions in segment/engine query behavior: IVF delete-churn widening and public doc-id tie-breaking for flat queries

Testing

  • cargo fmt --all --check
  • cargo test

Open with Devin

Summary by CodeRabbit

  • New Features

    • Full CLI shipped: create/init, create-from-schema, JSONL ingest (insert/upsert/update), query/fetch, index/column management, flush/optimize, and stats/options commands with tunable index/search flags.
  • Improved Search

    • Candidate selection and probe budgeting refined to better handle deleted/visible records and preserve recall.
    • Top-k behavior: results now include all items tied at the cutoff score (no deterministic doc-id tie-breaker).
    • Index tuning values render more cleanly in CLI outputs.
  • Tests

    • Expanded CLI and index/segment tests covering top-k, IVF/HNSW scenarios, JSONL validation, and DDL flows.

@coderabbitai

coderabbitai Bot commented Apr 3, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a modular CLI (cli/command/parsing) and moves command handling out of main; refactors segment search candidate-sizing and top-k/IVF nprobe logic (introducing CandidateNprobeInput, index_doc_count, and stored_doc_count), updates tests, and adds small API/trait helpers across crates.

Changes

Cohort / File(s) Summary
CLI surface & dispatcher
garuda/src/cli.rs, garuda/src/command.rs, garuda/src/parsing.rs, garuda/src/main.rs
New Cli/Command clap definitions, parsing utilities for JSONL/vectors/index params, run_command dispatcher, and simplified main.rs delegating CLI behavior.
Segment search core
crates/garuda-segment/src/search.rs
Refactored candidate sizing and IVF/HNSW wiring: added CandidateNprobeInput, replaced positional args with input structs, introduced stored_doc_count vs index_doc_count, tightened hides_deleted logic, and updated stats/count handling.
Search/top-k & nprobe tests
crates/garuda-segment/src/search_top_k_tests.rs, crates/garuda-segment/src/search_candidate_nprobe_tests.rs, crates/garuda-segment/tests/test_ivf_sidecar.rs
Added top-k unit tests; updated candidate-nprobe tests to use CandidateNprobeInput and added test for hard-deleted vs stored counts; reordered imports.
Flat index ordering & tests
crates/garuda-index-flat/src/lib.rs, crates/garuda-index-flat/tests/test_flat_index.rs
Changed hit truncation to include all hits tied at cutoff score (may return >TopK) and updated tests to assert membership of tied hits.
Engine ordering tests
crates/garuda-engine/tests/test_collection_ordering_behavior.rs
Split/renamed tests to verify doc-id tie-break both within single segment and after forced segment split/merge (segment_max_docs = 1).
CLI contract tests
garuda/tests/test_cli_contract.rs
Expanded integration tests for create/create-from-schema, JSONL insert/update/upsert, vector & by-id queries, fetch, index create/drop with params, column DDL, flush/optimize, and negative JSONL cases.
Meta & delete-store helper
crates/garuda-meta/src/lib.rs
Added DeleteStore::is_empty(&self) -> bool to expose emptiness check.
Index-scalar minor
crates/garuda-index-scalar/src/lib.rs
Simplified early-exit unwrap in prefilter_doc_ids (let predicates = predicates?;) with no behavior change.
Numeric newtype Display impls
crates/garuda-types/src/hnsw.rs, crates/garuda-types/src/ivf.rs
Added std::fmt::Display impls for several HNSW/IVF non-zero-u32 newtypes to allow numeric formatting.
Misc tests & imports
crates/garuda-segment/src/search_top_k_tests.rs, crates/garuda-segment/..., crates/garuda-engine/tests/...
Added/renamed tests to cover top-k widening, candidate sizing with deletions, IVF sidecar import ordering, and related behaviors.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as "CLI Parser\n(clap)"
    participant Cmd as "Command Dispatcher\n(run_command)"
    participant Parser as "Parsing Utils\n(read_jsonl/parse_index_params)"
    participant Engine as "Engine / Database"

    User->>CLI: provide argv
    CLI->>CLI: parse into `Cli` / `Command`
    CLI-->>Cmd: selected `Command`
    Cmd->>Engine: open database (root)
    Cmd->>Parser: parse inputs (JSONL, vector, index params)
    Parser-->>Cmd: typed args / JSON docs
    Cmd->>Engine: execute operation (create/insert/query/index/DDL)
    Engine-->>Cmd: result / status
    Cmd->>Parser: serialize output to JSON
    Parser-->>User: print JSON / status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

codex

Poem

🐰
I hopped through flags with whiskers keen,
Split main and tucked commands unseen.
Probes and top-k now skip and prance,
Tests cheer softly as code takes chance.
I nibble carrots, then skip to dance.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: CLI simplification and query regression fixes are both prominently addressed throughout the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/cli-simplify-and-fix-ci

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (8)
crates/garuda-segment/src/search.rs (1)

202-209: Consider renaming parameter indexed_doc_countcandidate_doc_count for consistency.

The search_ivf_hits function still uses the parameter name indexed_doc_count (line 207), but callers now pass stats.candidate_doc_count (line 180). The semantics have changed—this value now represents total records including deleted ones. Aligning the parameter name would improve clarity for future maintainers.

Same applies to ann_candidate_top_k at line 298.

♻️ Suggested rename
 fn search_ivf_hits(
     segment: SearchSegment<'_>,
     query_vector: &garuda_types::DenseVector,
     recall: garuda_types::IvfRecallPlan,
     candidate_top_k: TopK,
-    indexed_doc_count: usize,
+    candidate_doc_count: usize,
     visible_doc_count: usize,
     allowed_visible_doc_count: usize,
 ) -> Result<Vec<IvfSearchHit>, Status> {
 fn ann_candidate_top_k(
     top_k: TopK,
     budget: AnnBudgetPolicy,
     filter: SegmentFilterContext<'_>,
-    indexed_doc_count: usize,
+    candidate_doc_count: usize,
     visible_doc_count: usize,
 ) -> TopK {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/garuda-segment/src/search.rs` around lines 202 - 209, Rename the
misleading parameter `indexed_doc_count` to `candidate_doc_count` in the
function signature for `search_ivf_hits` and update all internal uses within
that function to reflect the new name, since callers now pass
`stats.candidate_doc_count`; likewise rename the `ann_candidate_top_k`
parameter/variable usage (the one referenced at line ~298) to match
`candidate_top_k`/`ann_candidate_top_k` naming consistency, and update any
callers or references to use the new identifier so semantics (total records
including deleted ones) are clear and consistent across `search_ivf_hits` and
ANN candidate handling.
garuda/src/cli.rs (1)

136-150: Consider using NonZeroUsize for top_k.

top_k is defined as usize, allowing 0, but TopK::new in command.rs will reject it at runtime. Using NonZeroUsize would provide earlier validation at the CLI parsing stage.

Suggested change
 #[derive(Args)]
 pub struct QueryArgs {
     #[arg(long)]
     pub value: String,
     #[arg(long)]
-    pub top_k: usize,
+    pub top_k: NonZeroUsize,

This would require updating command.rs to use top_k.get() when calling TopK::new.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@garuda/src/cli.rs` around lines 136 - 150, Change the QueryArgs struct's
top_k field from usize to std::num::NonZeroUsize so the CLI parser rejects 0
values early; update any call sites in command.rs that construct TopK (e.g.,
TopK::new(...)) to call .get() on top_k (TopK::new(top_k.get())) and adjust
types/parameter names accordingly wherever QueryArgs::top_k is used to compile
with the NonZeroUsize change.
garuda/src/command.rs (3)

27-34: Redundant CollectionOptions::default() calls.

Three separate CollectionOptions::default() calls are made. Consider caching the default once.

Suggested simplification
         } => {
+            let default_options = CollectionOptions::default();
             let options = CollectionOptions {
                 segment_max_docs: segment_max_docs
-                    .unwrap_or(CollectionOptions::default().segment_max_docs),
+                    .unwrap_or(default_options.segment_max_docs),
                 storage_access: storage_access
                     .map(Into::into)
-                    .unwrap_or(CollectionOptions::default().storage_access),
-                ..CollectionOptions::default()
+                    .unwrap_or(default_options.storage_access),
+                ..default_options
             };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@garuda/src/command.rs` around lines 27 - 34, Cache a single
CollectionOptions::default() and reuse it instead of calling it three times:
create let default = CollectionOptions::default(); then build options with
CollectionOptions { segment_max_docs:
segment_max_docs.unwrap_or(default.segment_max_docs), storage_access:
storage_access.map(Into::into).unwrap_or(default.storage_access), ..default } so
you reference the default fields only once; update the code around the options
variable accordingly.

17-19: Unreachable Command::Init arm.

The Init variant is already handled in main.rs before calling run_command, making this arm unreachable. Consider removing it or adding an unreachable!() macro to document the invariant.

Suggested change
 pub fn run_command(db: &Database, command: Command) -> Result<(), String> {
     match command {
-        Command::Init => Ok(()),
+        Command::Init => unreachable!("Init is handled in main.rs"),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@garuda/src/command.rs` around lines 17 - 19, The match arm handling
Command::Init inside run_command is unreachable because main.rs handles Init
before calling run_command; remove the Command::Init arm or replace its body
with unreachable!() to document the invariant. Locate the pattern match in the
run_command function and either delete the Command::Init => Ok(()) arm entirely
or change it to Command::Init => unreachable!() so the code and intent are
explicit.

184-192: Use of std::mem::take for value extraction is correct but could be cleaner.

The std::mem::take on args.value works, but since args is passed by value and consumed, you could destructure it instead for clarity.

Alternative approach
-fn id_query(mut args: QueryArgs) -> Result<VectorQuery, String> {
+fn id_query(args: QueryArgs) -> Result<VectorQuery, String> {
+    let QueryArgs { value, top_k, filter, include_vector, fields, search } = args;
     let mut query = VectorQuery::by_id(
         field_name(VECTOR_FIELD),
-        parse_doc_id(std::mem::take(&mut args.value))?,
-        TopK::new(args.top_k).map_err(|status| status.message)?,
+        parse_doc_id(value)?,
+        TopK::new(top_k).map_err(|status| status.message)?,
     );
-    apply_query_args(&mut query, args)?;
+    query.filter = filter;
+    query.output_fields = fields;
+    query.vector_projection = if include_vector {
+        VectorProjection::Include
+    } else {
+        VectorProjection::Exclude
+    };
+    query.search = parse_query_search(search)?;
     Ok(query)
 }

This eliminates the need for apply_query_args reuse at the cost of some duplication, but if you prefer the current structure, it's also acceptable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@garuda/src/command.rs` around lines 184 - 192, Replace the
std::mem::take(&mut args.value) pattern by destructuring the consumed QueryArgs
in id_query to extract the pieces you need (e.g., value and top_k) and use those
bindings when building the VectorQuery (call parse_doc_id on the extracted value
and TopK::new on the extracted top_k); because destructuring consumes args you
will need to either inline the small bits of logic currently in apply_query_args
for this case or reconstruct the remaining QueryArgs to pass into
apply_query_args, and then proceed to call apply_query_args or its inlined
equivalent before returning the query (refer to id_query, QueryArgs,
parse_doc_id, TopK::new, and apply_query_args to find the spots to change).
garuda/src/parsing.rs (1)

248-264: Potential precision loss for large unsigned integers.

Numbers that don't fit in i64 (like u64 values > i64::MAX) will be parsed as f64, which can lose precision for values > 2^53. This is a known limitation of JSON number handling.

If the domain requires large exact integers, consider checking as_u64() before as_f64(). For most use cases, this is acceptable.

Optional: Handle u64 explicitly if needed
 fn parse_scalar_value(value: serde_json::Value) -> Result<ScalarValue, String> {
     match value {
         serde_json::Value::Null => Ok(ScalarValue::Null),
         serde_json::Value::Bool(value) => Ok(ScalarValue::Bool(value)),
         serde_json::Value::Number(value) => {
             if let Some(value) = value.as_i64() {
                 return Ok(ScalarValue::Int64(value));
             }
+            // Note: Large u64 values would need ScalarType::UInt64 support
             if let Some(value) = value.as_f64() {
                 return Ok(ScalarValue::Float64(value));
             }
             Err(String::from("unsupported numeric value"))
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@garuda/src/parsing.rs` around lines 248 - 264, The parse_scalar_value
function currently converts JSON numbers by trying as_i64 then as_f64, which
causes precision loss for large unsigned integers; update parse_scalar_value to
check value.as_i64() first, then value.as_u64() and map to a new or existing
ScalarValue::UInt64 (or an appropriate UInt variant), and only then fallback to
value.as_f64(); ensure you update the ScalarValue enum if necessary to include a
UInt64 variant and adjust error handling/messages in parse_scalar_value
accordingly.
garuda/tests/test_cli_contract.rs (2)

388-420: Test failure reason may be misleading.

The test create_from_schema_requires_options_in_file expects failure due to missing options, but the schema also has an empty fields array while referencing primary_key: "pk". This would fail schema validation even if options were present. Consider either:

  1. Renaming the test to reflect it tests general invalid schema handling, or
  2. Adding a valid schema with only options missing to specifically test that requirement
Suggested fix for clearer test intent
 #[test]
 fn create_from_schema_requires_options_in_file() {
     let tmp = temp_path("cli-invalid-schema-file");
     std::fs::create_dir_all(&tmp).expect("create temp root");
     let schema_path = tmp.join("schema.json");

     std::fs::write(
         &schema_path,
         serde_json::json!({
             "schema": {
                 "name": "docs",
                 "primary_key": "pk",
-                "fields": [],
+                "fields": [
+                    {
+                        "name": "pk",
+                        "field_type": "String",
+                        "index": "None",
+                        "nullability": "Required",
+                        "default_value": null
+                    }
+                ],
                 "vector": {
                     "name": "embedding",
                     "dimension": 4,
                     "metric": "Cosine",
                     "indexes": "DefaultFlat"
                 }
             }
         })
         .to_string(),
     )
     .expect("write invalid schema file");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@garuda/tests/test_cli_contract.rs` around lines 388 - 420, The test
create_from_schema_requires_options_in_file is ambiguous because the provided
schema has an empty "fields" array while referencing primary_key "pk", causing
schema validation to fail for the wrong reason; update the test so it
specifically omits only the "options" field: modify the JSON in the test to
include a field entry for the primary key (e.g., an object with "name": "pk" and
appropriate "type") so the schema is otherwise valid, leaving out "options", or
alternatively rename the test to something like
create_from_schema_rejects_invalid_schema if you intend to cover general schema
validation; ensure run_cli still expects failure and keep the assert as-is.

24-26: Consider adding error context to stdout_json helper.

If JSON parsing fails, the current error message won't show the actual stdout content, making debugging difficult.

Suggested improvement
 fn stdout_json(output: &std::process::Output) -> Value {
-    serde_json::from_slice(&output.stdout).expect("stdout should be valid json")
+    serde_json::from_slice(&output.stdout).unwrap_or_else(|e| {
+        panic!(
+            "stdout should be valid json: {e}\nstdout: {}",
+            String::from_utf8_lossy(&output.stdout)
+        )
+    })
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@garuda/tests/test_cli_contract.rs` around lines 24 - 26, The helper
stdout_json currently calls
serde_json::from_slice(&output.stdout).expect("stdout should be valid json")
which loses the actual stdout content on parse failure; update the stdout_json
function to include the stdout bytes (decoded via String::from_utf8_lossy or
similar) in the error context or expect message so failures show the JSON parse
error plus the actual stdout content for debugging (refer to stdout_json and its
use of output.stdout).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/garuda-segment/src/search.rs`:
- Around line 202-209: Rename the misleading parameter `indexed_doc_count` to
`candidate_doc_count` in the function signature for `search_ivf_hits` and update
all internal uses within that function to reflect the new name, since callers
now pass `stats.candidate_doc_count`; likewise rename the `ann_candidate_top_k`
parameter/variable usage (the one referenced at line ~298) to match
`candidate_top_k`/`ann_candidate_top_k` naming consistency, and update any
callers or references to use the new identifier so semantics (total records
including deleted ones) are clear and consistent across `search_ivf_hits` and
ANN candidate handling.

In `@garuda/src/cli.rs`:
- Around line 136-150: Change the QueryArgs struct's top_k field from usize to
std::num::NonZeroUsize so the CLI parser rejects 0 values early; update any call
sites in command.rs that construct TopK (e.g., TopK::new(...)) to call .get() on
top_k (TopK::new(top_k.get())) and adjust types/parameter names accordingly
wherever QueryArgs::top_k is used to compile with the NonZeroUsize change.

In `@garuda/src/command.rs`:
- Around line 27-34: Cache a single CollectionOptions::default() and reuse it
instead of calling it three times: create let default =
CollectionOptions::default(); then build options with CollectionOptions {
segment_max_docs: segment_max_docs.unwrap_or(default.segment_max_docs),
storage_access:
storage_access.map(Into::into).unwrap_or(default.storage_access), ..default } so
you reference the default fields only once; update the code around the options
variable accordingly.
- Around line 17-19: The match arm handling Command::Init inside run_command is
unreachable because main.rs handles Init before calling run_command; remove the
Command::Init arm or replace its body with unreachable!() to document the
invariant. Locate the pattern match in the run_command function and either
delete the Command::Init => Ok(()) arm entirely or change it to Command::Init =>
unreachable!() so the code and intent are explicit.
- Around line 184-192: Replace the std::mem::take(&mut args.value) pattern by
destructuring the consumed QueryArgs in id_query to extract the pieces you need
(e.g., value and top_k) and use those bindings when building the VectorQuery
(call parse_doc_id on the extracted value and TopK::new on the extracted top_k);
because destructuring consumes args you will need to either inline the small
bits of logic currently in apply_query_args for this case or reconstruct the
remaining QueryArgs to pass into apply_query_args, and then proceed to call
apply_query_args or its inlined equivalent before returning the query (refer to
id_query, QueryArgs, parse_doc_id, TopK::new, and apply_query_args to find the
spots to change).

In `@garuda/src/parsing.rs`:
- Around line 248-264: The parse_scalar_value function currently converts JSON
numbers by trying as_i64 then as_f64, which causes precision loss for large
unsigned integers; update parse_scalar_value to check value.as_i64() first, then
value.as_u64() and map to a new or existing ScalarValue::UInt64 (or an
appropriate UInt variant), and only then fallback to value.as_f64(); ensure you
update the ScalarValue enum if necessary to include a UInt64 variant and adjust
error handling/messages in parse_scalar_value accordingly.

In `@garuda/tests/test_cli_contract.rs`:
- Around line 388-420: The test create_from_schema_requires_options_in_file is
ambiguous because the provided schema has an empty "fields" array while
referencing primary_key "pk", causing schema validation to fail for the wrong
reason; update the test so it specifically omits only the "options" field:
modify the JSON in the test to include a field entry for the primary key (e.g.,
an object with "name": "pk" and appropriate "type") so the schema is otherwise
valid, leaving out "options", or alternatively rename the test to something like
create_from_schema_rejects_invalid_schema if you intend to cover general schema
validation; ensure run_cli still expects failure and keep the assert as-is.
- Around line 24-26: The helper stdout_json currently calls
serde_json::from_slice(&output.stdout).expect("stdout should be valid json")
which loses the actual stdout content on parse failure; update the stdout_json
function to include the stdout bytes (decoded via String::from_utf8_lossy or
similar) in the error context or expect message so failures show the JSON parse
error plus the actual stdout content for debugging (refer to stdout_json and its
use of output.stdout).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6ae3745d-915a-4837-9187-5236967ca7f3

📥 Commits

Reviewing files that changed from the base of the PR and between 051abbc and 8ce761c.

📒 Files selected for processing (8)
  • crates/garuda-engine/tests/test_collection_ordering_behavior.rs
  • crates/garuda-segment/src/search.rs
  • crates/garuda-segment/tests/test_ivf_sidecar.rs
  • garuda/src/cli.rs
  • garuda/src/command.rs
  • garuda/src/main.rs
  • garuda/src/parsing.rs
  • garuda/tests/test_cli_contract.rs

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

@PhantomInTheWire PhantomInTheWire force-pushed the codex/cli-simplify-and-fix-ci branch from d8502ce to 134500d Compare April 3, 2026 19:23
coderabbitai[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@PhantomInTheWire PhantomInTheWire force-pushed the codex/cli-simplify-and-fix-ci branch from 8bc568d to ef077d8 Compare April 3, 2026 20:08
@PhantomInTheWire PhantomInTheWire force-pushed the codex/cli-simplify-and-fix-ci branch from ef077d8 to dfa9998 Compare April 3, 2026 20:08
@PhantomInTheWire PhantomInTheWire force-pushed the codex/cli-simplify-and-fix-ci branch from edc9e44 to 561669e Compare April 3, 2026 20:51
@PhantomInTheWire PhantomInTheWire force-pushed the codex/cli-simplify-and-fix-ci branch from 176bdcb to 1c3df88 Compare April 3, 2026 21:28
coderabbitai[bot]

This comment was marked as resolved.

@PhantomInTheWire PhantomInTheWire merged commit 7b2a40c into master Apr 4, 2026
5 checks passed
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