Skip to content

feat(containers): mutually exclusive image vs dockerfile, per-target cleanup, IDE schema hint#121

Merged
eFAILution merged 4 commits intofeat/argus-portabilityfrom
feat/containers-build-vs-image-and-schema-header
May 6, 2026
Merged

feat(containers): mutually exclusive image vs dockerfile, per-target cleanup, IDE schema hint#121
eFAILution merged 4 commits intofeat/argus-portabilityfrom
feat/containers-build-vs-image-and-schema-header

Conversation

@eFAILution
Copy link
Copy Markdown
Collaborator

Description

Three coupled UX improvements to the containers: config block, surfaced during the option-A review with the user.

Changes Made

  • Added new scanner/workflow
  • Modified existing scanner/workflow
  • Updated documentation
  • Fixed bug
  • Other (please specify)

Details

1. Schema option A — image: and dockerfile: are mutually exclusive

Before: each entry could declare image: and dockerfile: and context: together, with image: doing double duty as both pull source and build tag (the docker-compose pattern). After: each entry declares one shape:

Shape Keys Behavior
Remote pull image: (optional cleanup:) argus pulls and scans this exact reference
Build-then-scan dockerfile:, optional context:, name:, cleanup: argus runs docker build, tags as <name>:argus-scan, scans the result

Argus doesn't push images after building, so the compose image: tag-after-build semantic was never load-bearing for us. The cleaner separation reflects what the tool actually does.

Schema validator rejects entries with both keys with a clear remediation message:

❌ containers.images[0]: Image entry has both 'image:' and 'dockerfile:' set —
   these are mutually exclusive. Use 'image:' for remote pulls; use 'dockerfile:'
   (+ optional 'context:' and 'name:') for local builds. Argus does not push the
   build to a registry, so the 'image:' tag-after-build semantic from
   docker-compose is not supported.

Build entries auto-derive the on-disk image tag from name: (or from the Dockerfile path when name: is omitted) — same logic as argus scan container --discover, so explicit-config and auto-discovery produce the same image identifiers locally.

Stale configs that still set both keys log a warning and skip the entry instead of crashing the parser, so a half-migrated argus.yml still gets through the engine while surfacing the issue.

2. Per-target cleanup: override

cleanup: true|false on a single image entry overrides the engine-level default for that target only. Useful for the case where one base image should stay cached across runs while the rest of the dev images get torn down — set cleanup: false on the base entry, leave the others alone. None (the default) defers to the engine-wide setting.

containers:
  images:
    - dockerfile: docker/Dockerfile.base
      name: my-base
      cleanup: false   # keep this one cached
    - dockerfile: docker/Dockerfile.app
      name: my-app
                       # uses engine default (cleanup: true)

3. IDE schema directive in argus.yml

argus init already wrote a # yaml-language-server: $schema=... line at the top of generated configs. argus validate now warns when an existing config is missing it so users with hand-edited configs get a one-step path back to IDE-side schema validation in VS Code, IntelliJ, and similar tools.

The dogfood argus.yml and argus.example.yml both gain the directive at line 1.

Workflow update.github/workflows/build-containers.yml matrix preflight previously read .image from each argus.yml entry. The dogfood entries now use the build-only shape, so the yq query reads .name instead and the build step still produces the same ghcr.io/huntridge-labs/argus/<name>:<sha> tag for publishing.

Documentationargus.example.yml's containers: comment block was rewritten to walk through both shapes side by side, with the mutual-exclusion rule called out and the cleanup: per-target override documented.

Verification

  • argus validate: ✅ argus.yml is valid with the new shape; summary lists all 4 dogfood Dockerfiles
  • argus scan container --config argus.yml: 4 images built and scanned end-to-end (145 findings, 102 unique). Build tags surface as scanner-bandit:argus-scan etc., consistent with --discover.
  • argus validate against a config without the schema directive prints the IDE-hint warning; config with directive is silent
  • 1567 SDK tests pass (was 1557; +10 net)

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • Tested with different scanner combinations

Test Results

  • New schema validator tests: per-target cleanup type-checking; build-only-keys-on-remote-pulls warnings; the mutual-exclusion error
  • New CLI tests: schema-directive warning fires when missing, silent when present
  • New container discovery tests: per-target cleanup flows through; auto-derive name from Dockerfile path when name: omitted; defensive parser handling for stale configs with both keys
  • Existing tests that asserted the old image+dockerfile shape were updated to use option A

Security Considerations

  • No security impact

AI Context Updates (.ai/)

  • N/A - No .ai/ updates needed (no architecture or workflow changes; the conceptual shift is documented in argus.example.yml)

Checklist

  • Code follows project style guidelines
  • Documentation updated (argus.example.yml containers block + IDE-schema warning hint)
  • Changelog updated (if applicable)
  • All tests pass
  • Reviewed by at least one maintainer
  • Reviewed CONTRIBUTING.md guidelines

… cleanup, IDE schema hint

Three coupled UX improvements to the containers config block,
following the user's review of the option-A schema clarity question.

1. Schema option A: image and dockerfile are mutually exclusive.

   ``image:`` is for remote pulls only — argus pulls and scans the
   reference. ``dockerfile:`` (with optional ``context:`` and
   ``name:``) is for local build-then-scan. The previous shape
   doubled ``image:`` as both "pull source" and "tag the build as",
   which was the docker-compose precedent — argus doesn't push
   images after building, so the compose semantic was never
   load-bearing for us. The cleaner separation reflects what the
   tool actually does.

   Schema validator now rejects entries that have both keys with a
   clear remediation message. Build entries auto-derive the on-disk
   image tag from ``name:`` (or from the Dockerfile path when
   ``name:`` is omitted) — same logic as ``argus scan container
   --discover`` so explicit-config and auto-discovery produce the
   same image identifiers locally.

   Stale configs that still set both keys log a warning and skip the
   entry instead of crashing the parser, so a half-migrated argus.yml
   still gets through the engine while surfacing the issue.

2. Per-target ``cleanup:`` override.

   ``cleanup: true|false`` on a single image entry overrides the
   engine-level default for that target only. Useful for the case
   where one base image should stay cached across runs while the
   rest of the dev images are torn down — set ``cleanup: false`` on
   the base entry, leave the others alone. ``None`` (the default)
   defers to the engine-wide setting.

3. IDE schema directive in argus.yml.

   ``argus init`` already wrote a ``# yaml-language-server:
   $schema=...`` line at the top of generated configs. ``argus
   validate`` now warns when an existing config is missing that line
   so users with hand-edited configs get a one-step path back to
   IDE-side schema validation in VS Code, IntelliJ, and similar
   tools that speak the language-server-protocol YAML spec.

   The dogfood ``argus.yml`` and ``argus.example.yml`` both gain
   the directive at line 1.

Workflow update: ``.github/workflows/build-containers.yml`` matrix
preflight previously read ``.image`` from each argus.yml entry. The
dogfood entries now use the build-only shape, so the yq query reads
``.name`` instead and the build step still produces the same
``ghcr.io/huntridge-labs/argus/<name>:<sha>`` tag for publishing.

Documentation: argus.example.yml's ``containers:`` comment block was
rewritten to walk through both shapes side by side, with the
mutual-exclusion rule called out and the ``cleanup:`` per-target
override documented.

Tests: 1567 passing (was 1557; ten new). Existing tests that asserted
the old image+dockerfile shape were updated to use option A.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

E2E Test Coverage Report

Action E2E Test Status Notes
ai-summary ⚪ Exception Manual-only action - triggered via dedicated ai-summary.yml workflow with user-supplied PR number
comment-pr ⚪ Exception Utility action - tested indirectly by all scanner and linter actions
get-job-id ⚪ Exception Utility action - tested indirectly by other jobs
linter-dockerfile ✅ Tested
linter-javascript ✅ Tested
linter-json ✅ Tested
linter-python ✅ Tested
linter-terraform ✅ Tested
linter-yaml ✅ Tested
linting-summary ✅ Tested
parse-container-config ✅ Tested
parse-zap-config ✅ Tested
scanner-bandit ✅ Tested
scanner-checkov ✅ Tested
scanner-clamav ✅ Tested
scanner-codeql ✅ Tested
scanner-container ✅ Tested
scanner-container-summary ⚪ Exception Tested as part of scanner-container
scanner-dependency-review ✅ Tested
scanner-gitleaks ✅ Tested
scanner-opengrep ✅ Tested
scanner-osv ✅ Tested
scanner-supply-chain ✅ Tested
scanner-syft ✅ Tested
scanner-trivy-iac ✅ Tested
scanner-zap ✅ Tested
scanner-zap-summary ⚪ Exception Tested as part of scanner-zap
scn-detector ✅ Tested
security-summary ⚪ Exception Tested in test-summary job

Summary

  • Total Actions: 29
  • Covered: 29
  • Missing E2E Tests: 0
  • Coverage: 100%

✅ All Actions Have E2E Coverage

@codecov
Copy link
Copy Markdown

codecov Bot commented May 6, 2026

Codecov Report

❌ Patch coverage is 95.27559% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
argus/cli.py 72.22% 5 Missing ⚠️
argus/container/discovery.py 95.45% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

🔒 Argus Container Security Scan

Branch: feat/containers-build-vs-image-and-schema-header
Commit: d759e18

📊 Combined Findings Summary

🚨 Critical ⚠️ High 🟡 Medium 🔵 Low 📦 Total 🔢 Unique
1 22 67 64 154 154

Scanned: 4 containers | Build Failures: 0

📦 Container Breakdown

Container Image 🚨 Crit ⚠️ High 🟡 Med 🔵 Low Total Unique Status
cli ghcr.io/huntridge-labs/argus/cli:d759e18714426ce38646f547e5fb9886c816f712 1 11 16 1 29 29
scanner-bandit ghcr.io/huntridge-labs/argus/scanner-bandit:d759e18714426ce38646f547e5fb9886c816f712 0 0 2 0 2 2
scanner-opengrep ghcr.io/huntridge-labs/argus/scanner-opengrep:d759e18714426ce38646f547e5fb9886c816f712 0 7 44 63 114 114
scanner-supply-chain ghcr.io/huntridge-labs/argus/scanner-supply-chain:d759e18714426ce38646f547e5fb9886c816f712 0 4 5 0 9 9

🔍 Detailed Findings by Container

🚨 cli - 29 vulnerabilities (23 unique)

Image: ghcr.io/huntridge-labs/argus/cli:d759e18714426ce38646f547e5fb9886c816f712

Combined (Deduplicated)

🚨 Critical ⚠️ High 🟡 Medium 🔵 Low Total Unique
1 11 16 1 29 23
🔷 Trivy Scanner (29 findings, 23 unique)
CVE Severity Package Version Fixed
CVE-2025-68121 🚨 CRITICAL stdlib v1.24.11 1.24.13, 1.25.7, 1.26.0-rc.3
CVE-2026-32280 ⚠️ HIGH stdlib v1.26.1 1.25.9, 1.26.2
CVE-2026-32281 ⚠️ HIGH stdlib v1.26.1 1.25.9, 1.26.2
CVE-2026-32283 ⚠️ HIGH stdlib v1.26.1 1.25.9, 1.26.2
CVE-2026-33810 ⚠️ HIGH stdlib v1.26.1 1.26.2
CVE-2025-61726 ⚠️ HIGH stdlib v1.24.11 1.24.12, 1.25.6
CVE-2025-61728 ⚠️ HIGH stdlib v1.24.11 1.24.12, 1.25.6
CVE-2026-25679 ⚠️ HIGH stdlib v1.24.11 1.25.8, 1.26.1
CVE-2026-32280 ⚠️ HIGH stdlib v1.24.11 1.25.9, 1.26.2
CVE-2026-32281 ⚠️ HIGH stdlib v1.24.11 1.25.9, 1.26.2
CVE-2026-32283 ⚠️ HIGH stdlib v1.24.11 1.25.9, 1.26.2
CVE-2026-34040 ⚠️ HIGH github.com/docker/docker v28.5.2+incompatible 29.3.1
CVE-2026-3219 🟡 MEDIUM pip 26.0.1 N/A
CVE-2026-6357 🟡 MEDIUM pip 26.0.1 26.1
CVE-2026-32282 🟡 MEDIUM stdlib v1.26.1 1.25.9, 1.26.2
CVE-2026-32288 🟡 MEDIUM stdlib v1.26.1 1.25.9, 1.26.2
CVE-2026-32289 🟡 MEDIUM stdlib v1.26.1 1.25.9, 1.26.2
CVE-2025-11579 🟡 MEDIUM github.com/nwaples/rardecode/v2 v2.1.0 2.2.0
CVE-2025-58058 🟡 MEDIUM github.com/ulikunitz/xz v0.5.12 0.5.15
CVE-2025-47914 🟡 MEDIUM golang.org/x/crypto v0.35.0 0.45.0
CVE-2025-58181 🟡 MEDIUM golang.org/x/crypto v0.35.0 0.45.0
CVE-2025-61730 🟡 MEDIUM stdlib v1.24.11 1.24.12, 1.25.6
CVE-2026-27142 🟡 MEDIUM stdlib v1.24.11 1.25.8, 1.26.1
CVE-2026-32282 🟡 MEDIUM stdlib v1.24.11 1.25.9, 1.26.2
CVE-2026-32288 🟡 MEDIUM stdlib v1.24.11 1.25.9, 1.26.2
CVE-2026-32289 🟡 MEDIUM stdlib v1.24.11 1.25.9, 1.26.2
CVE-2026-33997 🟡 MEDIUM github.com/docker/docker v28.5.2+incompatible 29.3.1
CVE-2026-41506 🟡 MEDIUM github.com/go-git/go-git/v5 v5.17.2 5.18.0
CVE-2026-27139 🔵 LOW stdlib v1.24.11 1.25.8, 1.26.1
⚓ Grype Scanner (0 findings, 0 unique)

✅ No vulnerabilities detected by Grype

🟡 scanner-bandit - 2 vulnerabilities (2 unique)

Image: ghcr.io/huntridge-labs/argus/scanner-bandit:d759e18714426ce38646f547e5fb9886c816f712

Combined (Deduplicated)

🚨 Critical ⚠️ High 🟡 Medium 🔵 Low Total Unique
0 0 2 0 2 2
🔷 Trivy Scanner (2 findings, 2 unique)
CVE Severity Package Version Fixed
CVE-2026-3219 🟡 MEDIUM pip 26.0.1 N/A
CVE-2026-6357 🟡 MEDIUM pip 26.0.1 26.1
⚓ Grype Scanner (0 findings, 0 unique)

✅ No vulnerabilities detected by Grype

⚠️ scanner-opengrep - 114 vulnerabilities (50 unique)

Image: ghcr.io/huntridge-labs/argus/scanner-opengrep:d759e18714426ce38646f547e5fb9886c816f712

Combined (Deduplicated)

🚨 Critical ⚠️ High 🟡 Medium 🔵 Low Total Unique
0 7 44 63 114 50
🔷 Trivy Scanner (114 findings, 49 unique)
CVE Severity Package Version Fixed
CVE-2026-4878 ⚠️ HIGH libcap2 1:2.75-10+b8 N/A
CVE-2025-69720 ⚠️ HIGH libncursesw6 6.5+20250216-2 N/A
CVE-2026-29111 ⚠️ HIGH libsystemd0 257.9-1~deb13u1 N/A
CVE-2025-69720 ⚠️ HIGH libtinfo6 6.5+20250216-2 N/A
CVE-2026-29111 ⚠️ HIGH libudev1 257.9-1~deb13u1 N/A
CVE-2025-69720 ⚠️ HIGH ncurses-base 6.5+20250216-2 N/A
CVE-2025-69720 ⚠️ HIGH ncurses-bin 6.5+20250216-2 N/A
CVE-2026-27456 🟡 MEDIUM bsdutils 1:2.41-5 N/A
CVE-2026-3184 🟡 MEDIUM bsdutils 1:2.41-5 N/A
CVE-2026-27456 🟡 MEDIUM libblkid1 2.41-5 N/A
CVE-2026-3184 🟡 MEDIUM libblkid1 2.41-5 N/A
CVE-2026-4046 🟡 MEDIUM libc-bin 2.41-12+deb13u2 N/A
CVE-2026-4437 🟡 MEDIUM libc-bin 2.41-12+deb13u2 N/A
CVE-2026-4438 🟡 MEDIUM libc-bin 2.41-12+deb13u2 N/A
CVE-2026-5435 🟡 MEDIUM libc-bin 2.41-12+deb13u2 N/A
CVE-2026-5450 🟡 MEDIUM libc-bin 2.41-12+deb13u2 N/A
CVE-2026-5928 🟡 MEDIUM libc-bin 2.41-12+deb13u2 N/A
CVE-2026-6238 🟡 MEDIUM libc-bin 2.41-12+deb13u2 N/A
CVE-2026-4046 🟡 MEDIUM libc6 2.41-12+deb13u2 N/A
CVE-2026-4437 🟡 MEDIUM libc6 2.41-12+deb13u2 N/A
CVE-2026-4438 🟡 MEDIUM libc6 2.41-12+deb13u2 N/A
CVE-2026-5435 🟡 MEDIUM libc6 2.41-12+deb13u2 N/A
CVE-2026-5450 🟡 MEDIUM libc6 2.41-12+deb13u2 N/A
CVE-2026-5928 🟡 MEDIUM libc6 2.41-12+deb13u2 N/A
CVE-2026-6238 🟡 MEDIUM libc6 2.41-12+deb13u2 N/A
CVE-2026-27456 🟡 MEDIUM liblastlog2-2 2.41-5 N/A
CVE-2026-3184 🟡 MEDIUM liblastlog2-2 2.41-5 N/A
CVE-2026-34743 🟡 MEDIUM liblzma5 5.8.1-1 N/A
CVE-2026-27456 🟡 MEDIUM libmount1 2.41-5 N/A
CVE-2026-3184 🟡 MEDIUM libmount1 2.41-5 N/A
CVE-2026-27456 🟡 MEDIUM libsmartcols1 2.41-5 N/A
CVE-2026-3184 🟡 MEDIUM libsmartcols1 2.41-5 N/A
CVE-2026-40225 🟡 MEDIUM libsystemd0 257.9-1~deb13u1 N/A
CVE-2026-40226 🟡 MEDIUM libsystemd0 257.9-1~deb13u1 N/A
CVE-2026-4105 🟡 MEDIUM libsystemd0 257.9-1~deb13u1 N/A
CVE-2026-40225 🟡 MEDIUM libudev1 257.9-1~deb13u1 N/A
CVE-2026-40226 🟡 MEDIUM libudev1 257.9-1~deb13u1 N/A
CVE-2026-4105 🟡 MEDIUM libudev1 257.9-1~deb13u1 N/A
CVE-2026-27456 🟡 MEDIUM libuuid1 2.41-5 N/A
CVE-2026-3184 🟡 MEDIUM libuuid1 2.41-5 N/A
CVE-2026-27456 🟡 MEDIUM login 1:4.16.0-2+really2.41-5 N/A
CVE-2026-3184 🟡 MEDIUM login 1:4.16.0-2+really2.41-5 N/A
CVE-2026-27456 🟡 MEDIUM mount 2.41-5 N/A
CVE-2026-3184 🟡 MEDIUM mount 2.41-5 N/A
CVE-2026-5958 🟡 MEDIUM sed 4.9-2 N/A
CVE-2026-5704 🟡 MEDIUM tar 1.35+dfsg-3.1 N/A
CVE-2026-27456 🟡 MEDIUM util-linux 2.41-5 N/A
CVE-2026-3184 🟡 MEDIUM util-linux 2.41-5 N/A
CVE-2026-27171 🟡 MEDIUM zlib1g 1:1.3.dfsg+really1.3.1-1+b1 N/A
CVE-2026-3219 🟡 MEDIUM pip 26.0.1 N/A

...and 64 more

⚓ Grype Scanner (0 findings, 0 unique)

✅ No vulnerabilities detected by Grype

⚠️ scanner-supply-chain - 9 vulnerabilities (9 unique)

Image: ghcr.io/huntridge-labs/argus/scanner-supply-chain:d759e18714426ce38646f547e5fb9886c816f712

Combined (Deduplicated)

🚨 Critical ⚠️ High 🟡 Medium 🔵 Low Total Unique
0 4 5 0 9 9
🔷 Trivy Scanner (9 findings, 9 unique)
CVE Severity Package Version Fixed
CVE-2026-32280 ⚠️ HIGH stdlib v1.26.1 1.25.9, 1.26.2
CVE-2026-32281 ⚠️ HIGH stdlib v1.26.1 1.25.9, 1.26.2
CVE-2026-32283 ⚠️ HIGH stdlib v1.26.1 1.25.9, 1.26.2
CVE-2026-33810 ⚠️ HIGH stdlib v1.26.1 1.26.2
CVE-2026-3219 🟡 MEDIUM pip 26.0.1 N/A
CVE-2026-6357 🟡 MEDIUM pip 26.0.1 26.1
CVE-2026-32282 🟡 MEDIUM stdlib v1.26.1 1.25.9, 1.26.2
CVE-2026-32288 🟡 MEDIUM stdlib v1.26.1 1.25.9, 1.26.2
CVE-2026-32289 🟡 MEDIUM stdlib v1.26.1 1.25.9, 1.26.2
⚓ Grype Scanner (0 findings, 0 unique)

✅ No vulnerabilities detected by Grype


Generated by Argus

…s output

The container-scan handler ``_cmd_container_scan`` never called
``get_logger("argus", verbose=...)`` like the source-scan handler
does at the top of its body. Without that setup, the ``argus`` logger
has no console handler attached, so every engine-level
``logger.info()`` and ``logger.debug()`` call drops on the floor.
Result: ``argus scan container --verbose`` produced a blank terminal
that just sat there for the duration of the scan, with no signal at
all about which image was being processed or which phase it was in.

Add the ``get_logger`` call inside the handler — same shape as the
source-scan path — so verbose mode now streams the full per-image,
per-phase log: which container is processing, which sub-scanner is
running, when the vulnerability DB updates, what tool stderr looks
like on failure, etc.

Verified locally: argus scan container --verbose now prints
``Scanning 1 container(s)``, ``[1/1] Processing scanner-bandit``,
``Running trivy via container``, ``Updating trivy vulnerability DB``,
and so on as each phase progresses.
eFAILution added 2 commits May 6, 2026 10:11
Two coupled UX improvements that close the "I don't know what argus
is stuck on" gap surfaced during the option-A schema review.

1. Phase-aware container scan progress.

   ContainerEngine accepts an optional ``progress_callback`` that's
   invoked at each phase transition per image: ``pull``/``build`` on
   start, ``scan`` after build completes, ``done`` on success or
   failure. The CLI installs a callback that routes phase events to
   the right surface based on the user's flag mix:

   * Default (TTY): the spinner's status text updates in place
     (``[2/4] scanner-opengrep — scan (12s)`` instead of the static
     "Running container scan").
   * --no-spinner OR non-TTY: phase events print as persistent
     ``[idx/total] name — phase (Ns)`` lines on stderr — useful for
     CI logs and step-away terminals where the rolling spinner is
     useless.
   * --quiet: no-op (phase progress suppressed).
   * --verbose / --debug: no-op (the logger already streams full
     INFO/DEBUG output; the progress emitter would just duplicate it).

2. Verbosity flag re-shape — three orthogonal flags, one mental
   model per flag.

   The ``-v`` / ``--verbose`` / ``-vv`` ladder was confusing.
   Replace with named flags whose names announce their purpose:

   * (no flag) — phase-aware spinner with INFO-level engine logging.
     The user sees enough to know the scan is making progress.
   * --quiet / -q — suppress per-phase INFO lines and bump the
     engine logger to WARNING. The spinner still draws unless
     --no-spinner is also passed; final summary still prints.
   * --debug — full firehose: subprocess output, DB updates, every
     engine log line. ``--verbose`` is preserved as a backward-
     compatible alias so existing CI scripts keep working.

   The ``--quiet`` and ``--no-spinner`` flags target different
   concerns and compose orthogonally:
     * --quiet (log verbosity): suppress info messages
     * --no-spinner (UI rendering): don't draw the animation
   This matches *nix convention — git -q, pip -q, pytest -q all
   suppress info but don't touch UI rendering.

   New helper _configure_logger(args) maps the flag combination to
   a stream-handler level: --verbose/--debug to DEBUG, --quiet to
   WARNING, default to INFO. _cmd_container_scan now uses it.

Tests: 1580 passing (was 1567; ten more progress-emitter tests
covering each combination of --quiet, --verbose, --debug,
--no-spinner, and TTY-vs-non-TTY routing).

CLI reference regenerated for the new flags.
The four output-control flags (--quiet, --no-spinner, --debug,
--verbose) each get individual help text in the auto-generated per-
command tables, but the *compose pattern* — the orthogonality of log-
verbosity (--quiet) vs UI rendering (--no-spinner) and the four UX
modes that fall out — wasn't anywhere in the docs. The cli-reference
header warns "Do not edit manually", so the new section is added via
``scripts/ci/gen_cli_docs.py`` so it survives every regeneration.

Section sits between Global Options and Commands, displaying a four-
row table with When-to-use and What-you-see columns plus a one-line
note on the additional modes that fall out from composing flags.
@eFAILution eFAILution merged commit 519afe0 into feat/argus-portability May 6, 2026
72 checks passed
@eFAILution eFAILution deleted the feat/containers-build-vs-image-and-schema-header branch May 6, 2026 14:31
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