Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/major-remove-logs-cached-logs-alias.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions docs/adr/60933-remove-logs-cached-logs-flag-alias.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# ADR-60933: Remove `gh aw logs` `--cached-logs` Flag Alias

**Date**: 2026-09-14
**Status**: Draft
**Deciders**: gh-aw maintainers

---

### Context

[ADR-60702](60702-support-wildcard-cached-logs-files.md) introduced wildcard cached logs shards for `gh aw logs` and, as part of that change, added a `--cached-logs` alias alongside the existing `--cached-jsonl` flag. The alias created two spellings for the same input: both flags fed the same cached JSONL resolution path, help text had to describe both, and documentation examples drifted between them. Wildcard cache support does not depend on the alias, so the CLI surface carried a duplicate flag name without any capability of its own.

### Decision

We will remove the `--cached-logs` flag from the `logs` command and read cached log input only from `--cached-jsonl`. Wildcard cache prefixes such as `logs-*` remain fully supported, but exclusively through `--cached-jsonl`. Help text, examples, and CLI reference documentation are updated to show wildcard usage on `--cached-jsonl`, and flag-registration tests assert that `--cached-logs` is no longer registered.

This ADR amends only the neutral consequence in ADR-60702 stating that the CLI surface grows by one alias; ADR-60702's wildcard shard loading, unique shard naming, deterministic ordering, and date-range pruning decisions remain in force and are recorded there unchanged.

### Alternatives Considered

#### Alternative 1: Keep the alias and deprecate it gradually

The alias could remain registered but hidden or flagged as deprecated, with a warning pointing users to `--cached-jsonl`. This was considered because it avoids breaking any caller that already adopted the alias. It was not chosen because the alias shipped only very recently alongside the wildcard feature, so adoption is minimal, and a deprecation path would keep duplicate flag handling, help text, and tests alive for multiple releases.

#### Alternative 2: Keep `--cached-logs` and remove `--cached-jsonl` instead

The command could standardize on the newer alias name and drop the older flag. This was considered because `--cached-logs` reads more naturally for the logs command. It was not chosen because `--cached-jsonl` is the long-standing documented flag, is referenced by existing automation, and names the concrete cache format the flag accepts.

### Consequences

#### Positive
- The `logs` command exposes exactly one flag for cached JSONL input, so help text and documentation no longer describe the same input twice.
- Flag wiring and tests are simpler: a single option field feeds cached log resolution.
- Wildcard cache behavior is documented in one place, reducing the chance of examples drifting between flag names.

#### Negative
- Callers that adopted `--cached-logs` will fail with an unknown flag error and must switch to `--cached-jsonl`.
- The change is a breaking CLI change and requires a major changeset even though the removed surface is small.

#### Neutral
- Wildcard cache resolution, shard naming, merge ordering, and pruning behavior are unchanged.
- ADR-60702 remains the record of the wildcard cache design; this ADR narrows only its flag surface.

---

*ADR created by [adr-writer agent]. Review and finalize before changing status from Draft to Accepted.*
6 changes: 3 additions & 3 deletions docs/src/content/docs/setup/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -510,16 +510,16 @@ cat run-ids.txt | gh aw logs --stdin --repo owner/repo # required for bare num
gh aw logs --runtime gvisor # Filter to runs using a specific sandbox agent runtime
```

**Options:** `--after-run-id`, `--artifacts`, `--before-run-id`, `--cache-before`, `--cached-jsonl`, `--cached-logs`, `--count/-c`, `--end-date`, `--engine/-e`, `--evals`, `--exclude-staged`, `--filtered-integrity`, `--firewall`, `--format`, `--json/-j`, `--last`, `--no-firewall`, `--output/-o`, `--parse`, `--ref`, `--report-file`, `--repo/-r`, `--runtime`, `--safe-output`, `--start-date`, `--stdin`, `--summary-file`, `--timeout`, `--tool-graph`, `--train`
**Options:** `--after-run-id`, `--artifacts`, `--before-run-id`, `--cache-before`, `--cached-jsonl`, `--count/-c`, `--end-date`, `--engine/-e`, `--evals`, `--exclude-staged`, `--filtered-integrity`, `--firewall`, `--format`, `--json/-j`, `--last`, `--no-firewall`, `--output/-o`, `--parse`, `--ref`, `--report-file`, `--repo/-r`, `--runtime`, `--safe-output`, `--start-date`, `--stdin`, `--summary-file`, `--timeout`, `--tool-graph`, `--train`

`logs` defaults `--artifacts` to `usage` for faster, compact downloads. The `--last` flag is an alias for `--count/-c`.
When multiple targets run concurrently, `--count` limits the combined number of workflow runs and `--timeout` limits the total wall-clock download time across all targets.

`--cached-jsonl` and its `--cached-logs` alias reuse compatible, schema-versioned run records and workflow-run discovery responses. They write exactly one JSON value per line, appending every complete `gh run list` payload before downloading artifacts and available GitHub API rate-limit reports after collection. Each enriched `run` record includes job execution data, sanitized MCP tool-call metadata, and available engine, model, runtime, and component versions for downstream dashboards. Raw tool errors, arguments, responses, and artifact bodies are excluded. Discovered runs therefore remain available when a timeout or API limit interrupts processing. Records from incompatible schema versions are ignored. Use `gh aw json-schema logs-jsonl` to generate the schema for each JSON Lines item.
`--cached-jsonl` reuses compatible, schema-versioned run records and workflow-run discovery responses. It writes exactly one JSON value per line, appending every complete `gh run list` payload before downloading artifacts and available GitHub API rate-limit reports after collection. Each enriched `run` record includes job execution data, sanitized MCP tool-call metadata, and available engine, model, runtime, and component versions for downstream dashboards. Raw tool errors, arguments, responses, and artifact bodies are excluded. Discovered runs therefore remain available when a timeout or API limit interrupts processing. Records from incompatible schema versions are ignored. Use `gh aw json-schema logs-jsonl` to generate the schema for each JSON Lines item.

Each safe-output entity recorded for a run (the same provider-neutral records surfaced in `usage/activity/summary.json`) is also appended as its own `safe_output_item` line immediately after the `run` record, carrying a `run_id` correlating it back to the run plus the entity's type, provider, durable ID, human-readable identifier, URL, and target/state metadata. These per-entity lines are informational projections of the `run` record's `safe_outputs` array and are ignored by the in-memory run cache used to skip already-downloaded runs.

Pass a trailing wildcard prefix such as `--cached-logs 'logs-*'` to load all matching `logs-*.jsonl` files as the starting cache and write newly downloaded data to a unique `logs-<unix-time>-<random>.jsonl` file. With `--start-date` or `--end-date`, wildcard cache files containing exclusively dated run records outside the requested range are deleted.
Pass a trailing wildcard prefix such as `--cached-jsonl 'logs-*'` to load all matching `logs-*.jsonl` files as the starting cache and write newly downloaded data to a unique `logs-<unix-time>-<random>.jsonl` file. With `--start-date` or `--end-date`, wildcard cache files containing exclusively dated run records outside the requested range are deleted.

#### `audit`

Expand Down
17 changes: 4 additions & 13 deletions pkg/cli/logs_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const logsCommandExampleTemplate = ` # Basic usage
%[1]s logs --json # JSON format (compact by default, use -v for full)
%[1]s logs --json -v # Full JSON with audit metadata
%[1]s logs --cached-jsonl logs.jsonl # Reuse matching records and append new results immediately
%[1]s logs --cached-logs 'logs-*' # Reuse logs-*.jsonl files and write new data to a unique logs-*.jsonl file
%[1]s logs --cached-jsonl 'logs-*' # Reuse logs-*.jsonl files and write new data to a unique logs-*.jsonl file
%[1]s logs --format tsv # Tab-separated (minimal, raw data)
%[1]s logs --format console # Decorated console tables (human-friendly)
%[1]s logs --format markdown # Cross-run security audit report (Markdown)
Expand Down Expand Up @@ -152,10 +152,10 @@ By default, only the compact usage artifact is downloaded (token usage, run meta
Use --artifacts all to download all artifacts, or specify individual sets such as
--artifacts agent,firewall to fetch only what you need.

Use --cached-jsonl (or --cached-logs) to reuse matching run records without downloading and processing their
Use --cached-jsonl to reuse matching run records without downloading and processing their
artifacts again. New results are appended immediately as JSON Lines. When a date range is specified,
cached run records outside that range are removed after collection; other record types are retained.
Pass a trailing wildcard prefix such as --cached-logs 'logs-*' to load all matching .jsonl files
Pass a trailing wildcard prefix such as --cached-jsonl 'logs-*' to load all matching .jsonl files
and write new records to a unique .jsonl file with the same prefix. In wildcard mode,
cached files containing exclusively dated run records outside the requested range are deleted.
Aggregate analysis may be approximate when compact cached records omit detailed data.
Expand Down Expand Up @@ -437,7 +437,7 @@ func loadCommonLogsOptions(cmd *cobra.Command) (LogsDownloadOptions, error) {
Format: getStringFlag(cmd, "format"),
ReportFile: getStringFlag(cmd, "report-file"),
ArtifactSets: getStringSliceFlag(cmd, "artifacts"),
CachedJSONL: getCachedLogsFlag(cmd),
CachedJSONL: getStringFlag(cmd, "cached-jsonl"),
}
options.IgnoreWorkflowRuns, err = parseIgnoredWorkflowRunIDs(getStringSliceFlag(cmd, "ignore-workflow-runs"))
if err != nil {
Expand Down Expand Up @@ -642,7 +642,6 @@ func addLogsCommandFlags(logsCmd *cobra.Command, validArtifactSets string) {
logsCmd.Flags().String("format", "", "Output format: console (decorated tables), tsv (tab-separated), pretty (cross-run report), markdown (cross-run Markdown). Default: compact agent-optimized output")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/codebase-design] This removes a flag (--cached-logs) that shipped in the released wildcard-cache feature (PR #60702, referenced in the 2026-09-14 weekly blog post as already live). Per this repo's Breaking CLI Rules, removing a flag always requires a major changeset with migration guidance — I don't see a new file added under .changeset/ in this diff.

💡 Suggested changeset

Add .changeset/major-remove-cached-logs-alias.md:

---
"gh-aw": major
---

Remove the `--cached-logs` alias for `--cached-jsonl` on `gh aw logs`.

**Migration:** replace `--cached-logs` with `--cached-jsonl` (including wildcard prefixes such as `--cached-jsonl 'logs-*'`).

Without this, the release script won't record the breaking change or generate migration notes in CHANGELOG.md.

@copilot please address this.

logsCmd.Flags().String("report-file", "", "Write --format markdown output directly to this file path instead of stdout (creates parent directories as needed)")
logsCmd.Flags().String("cached-jsonl", "", "Path to cached logs JSONL to reuse, append new results, and retain runs in the requested date range")
logsCmd.Flags().String("cached-logs", "", "Alias for --cached-jsonl; supports trailing wildcard prefixes such as 'logs-*'")
logsCmd.Flags().Int("last", 0, "Alias for --count/-c: number of recent runs to download")
logsCmd.Flags().StringSlice("artifacts", []string{"usage"}, "Artifact sets to download (default: usage — compact workflow metadata and usage data). Use 'all' for everything, or comma-separate sets. Valid sets: "+validArtifactSets)
logsCmd.Flags().String("cache-before", "", "(Cache eviction) Evict locally cached run folders for runs before this date, prior to downloading. Accepts deltas like -1d, -1w, -1mo (or explicit day counts like -30d), or an absolute date YYYY-MM-DD. Unlike --start-date, this only clears local cache and does not filter which runs are fetched.")
Expand All @@ -651,7 +650,6 @@ func addLogsCommandFlags(logsCmd *cobra.Command, validArtifactSets string) {
_ = logsCmd.Flags().MarkDeprecated("after", "use --cache-before")
logsCmd.Flags().Bool("stdin", false, "Read workflow run IDs or URLs from stdin (one per line) instead of discovering runs via the GitHub API")
logsCmd.MarkFlagsMutuallyExclusive("firewall", "no-firewall")
logsCmd.MarkFlagsMutuallyExclusive("cached-jsonl", "cached-logs")
}

func registerLogsCommandCompletions(logsCmd *cobra.Command) {
Expand All @@ -665,13 +663,6 @@ func getStringFlag(cmd *cobra.Command, name string) string {
return value
}

func getCachedLogsFlag(cmd *cobra.Command) string {
if cmd.Flags().Changed("cached-logs") {
return getStringFlag(cmd, "cached-logs")
}
return getStringFlag(cmd, "cached-jsonl")
}

func getStringSliceFlag(cmd *cobra.Command, name string) []string {
value, _ := cmd.Flags().GetStringSlice(name)
return value
Expand Down
15 changes: 1 addition & 14 deletions pkg/cli/logs_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,7 @@ func TestNewLogsCommand(t *testing.T) {
cachedJSONLFlag := flags.Lookup("cached-jsonl")
require.NotNil(t, cachedJSONLFlag, "Should have 'cached-jsonl' flag")
assert.Contains(t, cachedJSONLFlag.Usage, "cached logs JSONL")
cachedLogsFlag := flags.Lookup("cached-logs")
require.NotNil(t, cachedLogsFlag, "Should have 'cached-logs' flag")
assert.Contains(t, cachedLogsFlag.Usage, "wildcard")
assert.Nil(t, flags.Lookup("cached-logs"), "Should not have 'cached-logs' alias")
drain3WeightsFlag := flags.Lookup("drain3-weights")
require.NotNil(t, drain3WeightsFlag, "Should have 'drain3-weights' flag")
assert.Contains(t, drain3WeightsFlag.Usage, "existing Drain3 weights")
Expand Down Expand Up @@ -141,7 +139,6 @@ func TestLogsCommandFlagDefaults(t *testing.T) {
{"max-storage", "0"},
{"prune-older-runs", "false"},
{"cached-jsonl", ""},
{"cached-logs", ""},
{"drain3-weights", ""},
}

Expand Down Expand Up @@ -178,16 +175,6 @@ func TestLogsCommandCachedJSONLOption(t *testing.T) {
assert.Equal(t, "current.jsonl", opts.CachedJSONL)
}

func TestLogsCommandCachedLogsAliasOption(t *testing.T) {
cmd := NewLogsCommand()
require.NoError(t, cmd.Flags().Set("cached-logs", "logs-*"))

opts, err := loadCommonLogsOptions(cmd)

require.NoError(t, err)
assert.Equal(t, "logs-*", opts.CachedJSONL)
}

func TestLogsCommandDrain3WeightsOption(t *testing.T) {
cmd := NewLogsCommand()
require.NoError(t, cmd.Flags().Set("drain3-weights", "weights.json"))
Expand Down
Loading