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
70 changes: 70 additions & 0 deletions client_reference/output_and_verbosity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
title: "Output and verbosity"
description: "How the Kosli CLI writes output, what warnings mean, and how to control verbosity."
---

This page explains where the Kosli CLI writes its output, what `[warning]` messages mean, and how to control verbosity in scripts and CI/CD pipelines.

## Where output goes

The CLI splits its output across two streams:

- **stdout** — Command results: created object IDs, JSON, tables, and any value intended to be piped or captured.
- **stderr** — Warnings, debug lines, and the "new version available" update notice.

The **exit code** is the authoritative success or failure signal. A non-zero exit code means the command failed; zero means it succeeded, regardless of what appeared on stderr.

## Warning messages

Warnings are written in the form `[warning] <message>` and indicate a non-fatal condition that the CLI worked around. Examples:

```text
[warning] failed to get git repo info. <details>
[warning] Repo URL will not be reported, <details>
[warning] failed to remove evidence file <path>: <details>
```

Warnings:

- Are always written to **stderr**.
- **Never** affect the exit code.
- Are not errors — the command completed successfully.

If you see a warning in a pipeline that you have already validated end-to-end, it is safe to suppress it (see below). If a warning is new or unexpected, read the message and address the underlying cause.

## Verbosity controls

| Flag | Effect |
|---|---|
| _(default)_ | Errors and `[warning]` lines to stderr. Results to stdout. |
| `-q`, `--quiet` | Suppresses `[warning]` lines. Errors still print. |
| `--debug` | Adds `[debug]` lines to stderr. Overrides `--quiet`. |
| `--debug=false` | Explicit-off form. Useful when a parent process or env var has enabled debug and you want to disable it for one command. |

When both `--quiet` and `--debug` are set, `--debug` wins and a debug notice is printed explaining the override.

Both flags have equivalent environment variables, following the standard `KOSLI_` prefix:

- `KOSLI_QUIET=true`
- `KOSLI_DEBUG=true`

## Warnings in CI/CD pipelines

CI systems including Jenkins, Azure DevOps, Bitbucket Pipelines, and GitHub Actions multiplex stdout and stderr into a single build log. Some render stderr lines in red or with error-level styling. This makes non-fatal `[warning]` lines look alarming to pipeline reviewers even though they have no effect on the build.

Once you have validated a workflow end-to-end, add `--quiet` (or set `KOSLI_QUIET=true`) to the Kosli CLI invocations to keep build logs clean:

```shell
kosli attest generic --quiet ...
```

<Warning>
Avoid redirecting all of stderr to `/dev/null` (for example, `kosli ... 2>/dev/null`). That hides genuine error messages and makes failures much harder to diagnose. Prefer `--quiet`, which suppresses only `[warning]` lines and keeps real errors visible.
</Warning>

If you are capturing CLI output in a shell subshell and seeing debug or warning lines mixed into the captured value, see [CLI in subshell captures stderr](/troubleshooting/subshell_stderr).

## See also

- [kosli root command and global flags](/client_reference/kosli)
- [CLI in subshell captures stderr](/troubleshooting/subshell_stderr)
4 changes: 4 additions & 0 deletions client_reference/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ For installation instructions, see [Install the Kosli CLI](/getting_started/inst
## Commands

Browse the CLI commands using the sidebar navigation, or start with the [kosli](/client_reference/kosli) root command to see global flags and environment variable configuration.

## Output and verbosity

See [Output and verbosity](/client_reference/output_and_verbosity) for how the CLI uses stdout and stderr, what `[warning]` messages mean, and how to control output in scripts and CI/CD pipelines with `--quiet` and `--debug`.
6 changes: 6 additions & 0 deletions config/navigation.json
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@
"group": "General",
"pages": [
"client_reference/overview",
"client_reference/output_and_verbosity"
]
},
{
"group": "Top-level commands",
"pages": [
"client_reference/kosli",
"client_reference/kosli_attach-policy",
"client_reference/kosli_completion",
Expand Down
42 changes: 26 additions & 16 deletions scripts/update-cli-nav.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ def get_command_group(title):
cmd = title.replace('kosli ', '').strip()

if cmd == '':
return 'General'
return 'Top-level commands'

# Top-level commands (no subcommand)
parts = cmd.split(' ')
if len(parts) == 1:
# Single-word commands like 'search', 'version', 'status', etc.
return 'General'
return 'Top-level commands'

# Group by first word for multi-word commands
group_word = parts[0]
Expand All @@ -72,8 +72,8 @@ def get_command_group(title):
'attach': 'attach / detach',
'attest': 'attest',
'begin': 'begin',
'completion': 'General',
'config': 'General',
'completion': 'Top-level commands',
'config': 'Top-level commands',
'create': 'create',
'detach': 'attach / detach',
'diff': 'diff',
Expand All @@ -87,9 +87,9 @@ def get_command_group(title):
'rename': 'rename',
'report': 'report',
'request': 'request',
'search': 'General',
'search': 'Top-level commands',
'snapshot': 'snapshot',
'tag': 'General',
'tag': 'Top-level commands',
}

return group_map.get(group_word, group_word)
Expand All @@ -102,9 +102,9 @@ def build_nav_groups(docs_dir):
for filename in sorted(os.listdir(docs_dir)):
if not filename.endswith('.md'):
continue
# Skip the overview page — it's manually maintained and always
# inserted as the first page in the General group below.
if filename == 'overview.md':
# Skip manually-maintained intro pages; they are inserted into the
# General group below in a fixed order.
if filename in ('overview.md', 'output_and_verbosity.md'):
continue

filepath = os.path.join(docs_dir, filename)
Expand Down Expand Up @@ -132,14 +132,24 @@ def build_nav_groups(docs_dir):
groups_dict[group] = []
groups_dict[group].append(cmd['page'])

# Build ordered navigation groups
# Put General first, then alphabetical
nav_groups = []

if 'General' in groups_dict:
nav_groups.append({
# Build ordered navigation groups.
# 1. General — manually-maintained intro pages, fixed order.
# 2. Top-level commands — auto-generated single-word kosli commands.
# 3. Remaining command families in alphabetical order, prefixed 'kosli '.
nav_groups = [
{
'group': 'General',
'pages': ['client_reference/overview'] + groups_dict.pop('General'),
'pages': [
'client_reference/overview',
'client_reference/output_and_verbosity',
],
}
]

if 'Top-level commands' in groups_dict:
nav_groups.append({
'group': 'Top-level commands',
'pages': groups_dict.pop('Top-level commands'),
})

for group_name in sorted(groups_dict.keys()):
Expand Down
4 changes: 4 additions & 0 deletions troubleshooting/subshell_stderr.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ DIGEST="$(kosli fingerprint "${IMAGE_NAME}" --artifact-type=docker --debug=false
## Context

The Kosli CLI writes debug information to `stderr` and all other output to `stdout`. In a local terminal, a `$(subshell)` captures only `stdout`. However, in many CI workflows (including GitHub and GitLab), `stdout` and `stderr` are multiplexed together, causing debug output to leak into captured variables.

## See also

- [Output and verbosity](/client_reference/output_and_verbosity) — full reference for the CLI's stdout/stderr behavior, `[warning]` messages, and the `--quiet` and `--debug` flags.